url.c

さて、ここでまた突然、url.cの紹介です。
ここでは、url.c内に

・URLエンコード(パーセントエンコード)
・URLparse(構文解析、文字列処理でurlの中のいろいろな部分を取り出す)
・URLparameter parse(parameterを、配列に格納する)

の機能を作ります。
これらは、twitterでのmk_signatureや、http関係の処理をするときに役立ちます。
① URLエンコード
URLエンコードとは、パーセントエンコードとも呼ばれ、(なんかいまいちその違いなどよくわかりませんが)
半角英数字と「-」「.」「_」「~」の四文字(非予約文字)以外を、そのバイト列データを用いて表すもの。

詳しくはこちらを参照。
http://www.studyinghttp.net/cgi-bin/rfc.cgi?3986

「:」は「58」という値が入ったバイトの解釈であり、58=0x3Aなので「%3A」と表します。
「と」はUTF8方式だと二バイトで表され、「130」「198」という値の入ったバイト列の解釈なので、
130=0x82, 198=0xC6を用いて「%82%C6」と表されます。

例えば
http://tororo7.com/とろろ.jpg
をまるごとエンコードすると、
http%3A%2F%2Ftororo7%2Ecom%2F%82%C6%82%EB%82%EB%2Ejpg
となるわけです。

で、これだけだとそれこそ例のようなリクエストを送りたい時、
本来URLを作る前にやっておくべきですが、「とろろ」の部分だけencodeしたい時困ります。
そこで、予約文字と呼ばれる「:」「/」「.」などを除いてエンコードする関数も作りました。
それを用いると、ちゃんと
http://tororo7.com/%82%C6%82%EB%82%EB.jpg
になります。

やり方としては、エンコードした後の文字列のサイズを求めてmallocし、
sprintf関数でデータ内容を書き込んでいく、というもの。sprintfは、便利極まりないです。
これも含めてソースコードを下の方に載せますが、2パターンのエンコード関数、とても冗長になっていてごめんなさい…。
② URLparse
これはURL中の「://」や「/」や「?」や「=」をもとに、いろんな部分を取り出す、というもの。
文字を格納できる場所を受け取って、NULLでなければそこに書き込みます。
ただの文字列処理なので、特に内容の説明はしませんが、
返せる部分は
・protcol
・baseURL
・host
・pass
・parameter
の5つです。
http://hoge.com/hoge.html?q=hoge&len=10
だったら、
prot に http
base に http://hoge.com/hote.html
host に hoge.com
pass に /hoge.html?q=hoge&len=10
param に q=hoge&len=10
が格納されます。
baseやparamはtwitter.cのmk_signatureで必要です。
③ URLparameter parse
これは
「hoge=3&tororo=7」など、URL中のパラメーター部分を受け取って、
受け取った配列に格納するというもの。ちとその配列の受け取り方などややこしく書いてしまっております…。
やってることは単純、
 =まで読んでbufferに格納し、その大きさmallocしkey配列にそのポインタを与える。
 もう一回今度はvalue配列に与える。
 &があればもう一回自分自身を呼び出す。
といった感じです。

では、url.cを下に載せます。
#ifndef _URL
#define _URL

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *url_encode(char *s, int size);
char *url_encode_url(char *s, int size);
int url_unreserved(char c);
int url_reserved(char c);
void url_parse(char *url, char *prot, char *base, char *host, char *pass, char *param);
void url_parse_parameter(char *param, int *pnum, char **key, char **value);


char *url_encode(char *s, int size){
   int k, enn = 0;
   // get encoded size
   for(k = 0; k < size; ++k){
      if(url_unreserved(s[k])) enn += 1;
      else enn += 3;
   }
   char *en = (char *)malloc(sizeof(char) * (enn + 1));
   int ofst = 0;
   for(k = 0; k < size; ++k){
      if(url_unreserved(s[k])) en[ofst++] = s[k];
      else ofst += sprintf(en + ofst, "%%%02X", (unsigned char)s[k]);
   }
   en[ofst] = '\0';
   return en;
}

char *url_encode_url(char *s, int size){
   int k, enn = 0;
   // get encoded size
   for(k = 0; k < size; ++k){
      if(url_unreserved(s[k]) || url_reserved(s[k])) enn += 1;
      else enn += 3;
   }
   char *en = (char *)malloc(sizeof(char) * (enn + 1));
   int ofst = 0;
   for(k = 0; k < size; ++k){
      if(url_unreserved(s[k]) || url_reserved(s[k])) en[ofst++] = s[k];
      else ofst += sprintf(en + ofst, "%%%02X", (unsigned char)s[k]);
   }
   en[ofst] = '\0';
   return en;
}


int url_unreserved(char c){
   if('a' <= c && c <= 'z') return 1;
   if('0' <= c && c <= '9') return 1;
   if('A' <= c && c <= 'Z') return 1;
   if(c == '-' || c == '.' || c == '_' || c == '~') return 1;
   return 0;
}

int url_reserved(char c){
   if(c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || 
      c == ']' || c == '@' || c == '!' || c == '$' || c == '&' || 
      c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || 
      c == ',' || c == ';' || c == '=') return 1;
   else return 0;
}

// parse url => get protcol, baseurl, hostname, pass, parameter if isnot NULL
void url_parse(char *url, char *prot, char *base, char *host, char *pass, char *param){
   static char vain[500];
   if(prot == NULL) prot = vain;
   if(base == NULL) base = vain;
   if(host == NULL) host = vain;
   if(pass == NULL) pass = vain;
   if(param == NULL) param = vain;

// get protcol and baseurl and hostname
   while(*url != ':'){
      *(base++) = *url;
      *(prot++) = *url;
      url++;
   }
   *prot = '\0';
   *(base++) = *(url++);
   *(base++) = *(url++);
   *(base++) = *(url++);
   while(*url != '/' && *url != '\0'){
      *(base++) = *url;
      *(host++) = *url;
      url++;
   }
   *(base++) = *(url++);
   *host = '\0';
// get baseurl and pass+parameter
   *(pass++) = '/';
   while(*url != '?' && *url != '\0'){
      *(base++) = *url;
      *(pass++) = *url;
      url++;
   }
   *base = '\0';
// get bass+parameter and parameter
   if(*url == '?'){
      *(pass++) = *(url++);
      while(*url != '\0'){
   *(pass++) = *url;
   *(param++) = *url;
   url++;
      }
   }
   *pass = '\0';
   *param = '\0';
}

// parse parameter => loop input to key[*pnum], value[*pnum] and (*pnum)++
void url_parse_parameter(char *param, int *pnum, char **key, char **value){
   if(param[0] == '\0') return;
   int i;
   char keytmp[100], valtmp[100];
   i = 0;
   while(*param != '=') keytmp[i++] = *(param++);
   keytmp[i] = '\0';
   key[*pnum] = (char *)malloc(sizeof(char) * (i + 1));
   strcpy(key[*pnum], keytmp);
   param++;
   i = 0;
   while(*param != '&' && *param != '\0') valtmp[i++] = *(param++);
   valtmp[i] = '\0';
   value[*pnum] = (char *)malloc(sizeof(char) * (i + 1));
   strcpy(value[*pnum], valtmp);
   printf("[http_parse_parameter:%d]\nkey : \"%s\", val : \"%s\"\n", *pnum, key[*pnum], value[*pnum]);
   (*pnum)++;
   if(*param == '&') url_parse_parameter(param + 1, pnum, key, value);
}

#endif

コメントをお書きください

コメント: 2
  • #1

    seks telefon (金曜日, 03 11月 2017 19:30)

    sfeminizować

  • #2

    www (金曜日, 17 11月 2017 21:38)

    sprzędzionego