// ************************************************************************** // HTTPヘッダを受信して解析する。 // // 処理するのはGETのみ。GET以外のメソッドが来たらエラー // 今のところ、URIとuser_agent、Range、Hostを解析。 // URIは、URIデコードもやる。 // // return: 0 正常終了 // return: 0以外 エラー // ************************************************************************** static int http_header_receive(int accept_socket, HTTP_RECV_INFO *http_recv_info_p) { int result = 0; int recv_len; unsigned char line_buf[1024]; // 大きめに。 unsigned char work_buf[1024]; unsigned char work_buf2[1024]; unsigned char split1[1024]; unsigned char split2[1024]; int ret; int i; int j; // ================================ // 1行づつ HTTPヘッダを受信 // ================================ for (i=0;;i++) { // 1行受信 実行。 memset(line_buf, '\0', sizeof(line_buf)); recv_len = line_receive(accept_socket, line_buf, sizeof(line_buf)); // debug. 受信したヘッダ表示 debug_log_output("'%s'(%d byte)\n", line_buf, recv_len ); // 受信した内容をチェック。 if ( i != 0 && recv_len == 0 ) // 空行検知。ヘッダ受信終了。 { break; } else if ( recv_len < 0 ) // 受信失敗 { return ( -1 ); } // -------------------------- // GETメッセージチェック // -------------------------- if ( i == 0 ) // 1行目のみチェック { debug_log_output("URI Check start.'%s'\n", line_buf); // GET/POSTある? if (strncmp(line_buf, "GET ", 4) && strncmp(line_buf, "POST ", 5)) { debug_log_output("'GET' or 'POST' not found. error."); return ( -1 ); } strncpy(http_recv_info_p->request_method, line_buf, sizeof(http_recv_info_p->request_method)); cut_after_character(http_recv_info_p->request_method, ' '); // 最初のスペースまでを削除。 cut_before_character(line_buf, ' '); // 次にスペースが出てきたところの後ろまでを削除。 cut_after_character(line_buf, ' '); // =========================== // GETオプション部解析 // =========================== // REQUEST_URI用・Proxy用に値を保存 strncpy(http_recv_info_p->request_uri, line_buf, sizeof(http_recv_info_p->request_uri)); // '?'が存在するかチェック。 if ( strchr(line_buf, '?') != NULL ) { strncpy(work_buf, line_buf, sizeof(work_buf)); // '?'より前をカット cut_before_character(work_buf, '?' ); debug_log_output("work_buf = '%s'", work_buf ); while ( 1 ) { memset(split1, '\0', sizeof(split1)); memset(split2, '\0', sizeof(split2)); uri_decode(split1, sizeof(split1), work_buf, sizeof(work_buf) ); strcpy(work_buf, split1); // 最初に登場する'&'で分割 ret = sentence_split(work_buf, '&', split1, split2 ); if ( ret == 0 ) // 分割成功 { strncpy(work_buf, split2, sizeof(work_buf)); } else if (strlen(work_buf) > 0) // まだwork_bufに中身ある? { strncpy( split1, work_buf, sizeof(split1)); strncpy( work_buf, "", sizeof(work_buf)); } else // 処理終了 { break; } // ------------------------------------- // GETした内容 解析開始 // 超安直。いいのかこんな比較で。 // ------------------------------------- // URIデコード // uri_decode(work_buf2, sizeof(work_buf2), split1, sizeof(split1) ); strcpy(work_buf2, split1); // "page="あるか調査。 if (strncasecmp( work_buf2, "page=", strlen("page=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); if ( strlen(work_buf2) > 0 ) { // 構造体に値を保存。 http_recv_info_p->page = atoi(work_buf2); } continue; } // "menupage="あるか調査。 if (strncasecmp( work_buf2, "menupage=", strlen("menupage=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); if ( strlen(work_buf2) > 0 ) { // 構造体に値を保存。 http_recv_info_p->menupage = atoi(work_buf2); } continue; } // "title=" DVD title selection if (strncasecmp( work_buf2, "title=", strlen("title=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); if ( strlen(work_buf2) > 0 ) { // 構造体に値を保存。 http_recv_info_p->title = atoi(work_buf2); } continue; } if (strncasecmp( work_buf2, "width=", strlen("width=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); if ( strlen(work_buf2) > 0 ) { // 構造体に値を保存。 global_param.target_jpeg_width = atoi(work_buf2); } continue; } if (strncasecmp( work_buf2, "height=", strlen("height=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); if ( strlen(work_buf2) > 0 ) { // 構造体に値を保存。 global_param.target_jpeg_height = atoi(work_buf2); } continue; } // "action="あるか調査。 if (strncasecmp( work_buf2, "action=", strlen("action=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); // 構造体に値を保存。 strncpy(http_recv_info_p->action, work_buf2, sizeof(http_recv_info_p->action)); continue; } // "type=" allplay list type if (strncasecmp( work_buf2, "type=movie", strlen("type=movie") ) == 0 ) { http_recv_info_p->default_file_type = TYPE_MOVIE; continue; } if (strncasecmp( work_buf2, "type=music", strlen("type=music") ) == 0 ) { http_recv_info_p->default_file_type = TYPE_MUSIC; continue; } if (strncasecmp( work_buf2, "type=photo", strlen("type=photo") ) == 0 ) { http_recv_info_p->default_file_type = TYPE_JPEG; continue; } if (strncasecmp( work_buf2, "type=soundtrack", strlen("type=soundtrack") ) == 0 ) { http_recv_info_p->default_file_type = TYPE_MUSICLIST; continue; } if (strncasecmp( work_buf2, "type=slideshow", strlen("type=slideshow") ) == 0 ) { http_recv_info_p->default_file_type = TYPE_PLAYLIST; continue; } // "option="あるか調査 if (strncasecmp( work_buf2, "option=", strlen("option=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); // 構造体に値を保存。 strncpy(http_recv_info_p->option, work_buf2, sizeof(http_recv_info_p->option)); continue; } // "alias="あるか調査 if (strncasecmp( work_buf2, "alias=", strlen("alias=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); // 構造体に値を保存。 strncpy(http_recv_info_p->alias, work_buf2, sizeof(http_recv_info_p->alias)); if (strncasecmp(http_recv_info_p->alias, "movie", strlen("movie")) == 0) http_recv_info_p->default_file_type = TYPE_MOVIE; else if (strncasecmp(http_recv_info_p->alias, "music", strlen("music")) == 0) http_recv_info_p->default_file_type = TYPE_MUSIC; else if (strncasecmp(http_recv_info_p->alias, "photo", strlen("photo")) == 0) http_recv_info_p->default_file_type = TYPE_JPEG; else http_recv_info_p->default_file_type = TYPE_UNKNOWN; continue; } if (strncasecmp( work_buf2, "lsearch=", strlen("lsearch=") ) == 0 ) { cut_before_character(work_buf2, '='); strcpy(http_recv_info_p->lsearch, work_buf2); strcpy(http_recv_info_p->recv_uri, work_buf2); continue; } // "search= if (strncasecmp( work_buf2, "search", strlen("search") ) == 0 ) { if (strncasecmp(work_buf2, "search_movie", strlen("search_movie")) == 0) { http_recv_info_p->search_type = TYPE_MOVIE; strcpy(http_recv_info_p->search_str, "_movie"); http_recv_info_p->default_file_type = TYPE_MOVIE; // printf("search movie for "); } else if (strncasecmp(work_buf2, "search_music", strlen("search_music")) == 0) { http_recv_info_p->search_type = TYPE_MUSIC; strcpy(http_recv_info_p->search_str, "_music"); http_recv_info_p->default_file_type = TYPE_MUSIC; // printf("search music for "); } else if (strncasecmp(work_buf2, "search_photo", strlen("search_photo")) == 0) { http_recv_info_p->search_type = TYPE_JPEG; strcpy(http_recv_info_p->search_str, "_photo"); http_recv_info_p->default_file_type = TYPE_JPEG; // printf("search photo for "); } else if (strncasecmp(work_buf2, "search_all", strlen("search_all")) == 0) { http_recv_info_p->search_type = TYPE_UNKNOWN; strcpy(http_recv_info_p->search_str, "_all"); http_recv_info_p->default_file_type = TYPE_UNKNOWN; // printf("search all for "); } else continue; cut_before_character(work_buf2, '='); strncpy(http_recv_info_p->search, work_buf2, sizeof(http_recv_info_p->search)); if (http_recv_info_p->search[0] == '\0') // everything qualifies strcpy(http_recv_info_p->search, ".*"); // printf("%s\n", http_recv_info_p->search); continue; } // "sort="あるか調査 if (strncasecmp( work_buf2, "sort=", strlen("sort=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); // 構造体に値を保存。 strncpy(http_recv_info_p->sort, work_buf2, sizeof(http_recv_info_p->sort)); continue; } // "dvdopt="あるか調査 if (strncasecmp( work_buf2, "dvdopt=", strlen("dvdopt=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); // 構造体に値を保存。 strncpy(http_recv_info_p->dvdopt, work_buf2, sizeof(http_recv_info_p->dvdopt)); continue; } // "focus="あるか調査 if (strncasecmp( work_buf2, "focus=", strlen("focus=") ) == 0 ) { // = より前を削除 cut_before_character(work_buf2, '='); // 構造体に値を保存。 strncpy(http_recv_info_p->focus, work_buf2, sizeof(http_recv_info_p->focus)); continue; } } } debug_log_output("http_recv_info_p->page = '%d'", http_recv_info_p->page); debug_log_output("http_recv_info_p->title = '%d'", http_recv_info_p->title); debug_log_output("http_recv_info_p->action = '%s'", http_recv_info_p->action); debug_log_output("http_recv_info_p->option = '%s'", http_recv_info_p->option); debug_log_output("http_recv_info_p->dvdopt = '%s'", http_recv_info_p->dvdopt); // URIデコード cut_after_character(line_buf, '?'); uri_decode(work_buf, sizeof(work_buf), line_buf, sizeof(line_buf) ); strncpy(line_buf, work_buf, sizeof(line_buf)); debug_log_output("URI(decoded):'%s'\n", line_buf); convert_language_code(line_buf, work_buf, sizeof(work_buf), CODE_AUTO, CODE_EUC); debug_log_output("URI(decoded,euc,FYI):'%s'\n", work_buf); // 構造体に保存 if (http_recv_info_p->lsearch[0] == '\0') strncpy(http_recv_info_p->recv_uri, line_buf, sizeof(http_recv_info_p->recv_uri)); continue; } // User-agent切り出し if ( strncasecmp(line_buf, HTTP_USER_AGENT, strlen(HTTP_USER_AGENT) ) == 0 ) { // ':'より前を切る cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); // 構造体に保存 strncpy( http_recv_info_p->user_agent, line_buf, sizeof(http_recv_info_p->user_agent)); // Set the skin name based on user agent, if desired for(j=0; j<global_param.alternate_skin_count; j++) { debug_log_output("Checking for '%s'", global_param.alternate_skin_match[j]); if(strstr(line_buf, global_param.alternate_skin_match[j]) != NULL) { strcpy(global_param.skin_name, global_param.alternate_skin_name[j]); debug_log_output("User agent matches alternate skin '%s'", global_param.skin_name); break; } } continue; } // Rangeあるかチェック if ( strncasecmp(line_buf, HTTP_RANGE, strlen(HTTP_RANGE) ) == 0 ) { debug_log_output("%s Detect.\n", HTTP_RANGE); // ':' より前を切る。 cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); // recv_range にRangeの中身保存 strncpy(http_recv_info_p->recv_range, line_buf, sizeof(http_recv_info_p->recv_range)); // '=' より前を切る cut_before_character(line_buf, '='); // '-'で前後に分割。 sentence_split(line_buf, '-', work_buf, work_buf2); debug_log_output("work_buf='%s'\n", work_buf); debug_log_output("work_buf2='%s'\n", work_buf2); // 値を文字列→数値変換 http_recv_info_p->range_start_pos = strtoull(work_buf, NULL, 10); if ( strlen(work_buf2) > 0 ) { http_recv_info_p->range_end_pos = strtoull(work_buf2, NULL, 10); } debug_log_output("range_start_pos=%d\n", http_recv_info_p->range_start_pos); debug_log_output("range_end_pos=%d\n", http_recv_info_p->range_end_pos); continue; } // Hostあるかチェック if ( strncasecmp(line_buf, HTTP_HOST, strlen(HTTP_HOST) ) == 0 ) { debug_log_output("%s Detect.\n", HTTP_HOST); // ':' より前を切る。 cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); strncpy(http_recv_info_p->recv_host, line_buf, sizeof(http_recv_info_p->recv_host)); if(NULL == strchr(http_recv_info_p->recv_host, ':')) { debug_log_output("CLIENT BUG: Host header field was missing port number - fixing"); snprintf(http_recv_info_p->recv_host + strlen(http_recv_info_p->recv_host), sizeof(http_recv_info_p->recv_host)-1, ":%d", global_param.server_port); debug_log_output("%s '%s'", HTTP_HOST, http_recv_info_p->recv_host); } continue; } if (strncasecmp(line_buf, HTTP_AUTHORIZATION, strlen(HTTP_AUTHORIZATION)) == 0) { debug_log_output("%s Detect.\n", HTTP_AUTHORIZATION); // ':' より前を切る。 cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); if (strncmp(line_buf, "Basic ", 6)) { debug_log_output("received '%s', is not supported.", line_buf); continue; } strncpy(http_recv_info_p->passwd, line_buf + 6, sizeof(http_recv_info_p->passwd)); continue; } // Content-Lengthあるかチェック if ( strncasecmp(line_buf, HTTP_CONTENT_LENGTH_STR, strlen(HTTP_CONTENT_LENGTH_STR) ) == 0 ) { debug_log_output("%s Detect.\n", HTTP_CONTENT_LENGTH_STR); // ':' より前を切る。 cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); /* recv_content_length は わざと long です. */ http_recv_info_p->recv_content_length = strtol(line_buf, NULL, 10); debug_log_output("Content-Length: %ld", http_recv_info_p->recv_content_length); continue; } } return result; }
// ************************************************************************** // HTTPヘッダを受信して解析する。 // // 処理するのはGETのみ。GET以外のメソッドが来たらエラー // 今のところ、URIとuser_agent、Range、Hostを解析。 // URIは、URIデコードもやる。 // // return: 0 正常終了 // return: 0以外 エラー // ************************************************************************** static int http_header_receive(int accept_socket, HTTP_RECV_INFO *http_recv_info_p) { int result = 0; int recv_len; char line_buf[1024]; // 大きめに。 char work_buf[1024]; char work_buf2[1024]; char split1[1024]; char split2[1024]; int ret; int i; // ================================ // 1行づつ HTTPヘッダを受信 // ================================ for (i=0;;i++){ // 1行受信 実行。 recv_len = line_receive(accept_socket, line_buf, sizeof(line_buf)); // 受信した内容をチェック。 if ( recv_len == 0 ){ // 空行検知。ヘッダ受信終了。 break; }else if ( recv_len < 0 ){ // 受信失敗 return ( -1 ); } // debug. 受信したヘッダ表示 debug_log_output("'%s'(%d byte)\n", line_buf, recv_len ); // -------------------------- // GETメッセージチェック // -------------------------- if ( i == 0 ){ // 1行目のみチェック debug_log_output("%d:URI Check start.'%s'\n", accept_socket,line_buf); // GETある? if ( strstr(line_buf, "GET") != NULL ){ http_recv_info_p->isGet = 1; }else if ( strstr(line_buf, "HEAD") != NULL ){ http_recv_info_p->isGet = 2; }else if ( strstr(line_buf, "POST") != NULL ){ http_recv_info_p->isGet = 3; }else{ debug_log_output("'GET' not found. error.%d",accept_socket); return ( -1 ); } // 最初のスペースまでを削除。 cut_before_character(line_buf, ' '); // 次にスペースが出てきたところの後ろまでを削除。 cut_after_character(line_buf, ' '); // =========================== // GETオプション部解析 // =========================== // REQUEST_URI用・Proxy用に値を保存 strncpy(http_recv_info_p->request_uri, line_buf, sizeof(http_recv_info_p->request_uri)); // '?'が存在するかチェック。 if ( strchr(line_buf, '?') != NULL ){ strncpy(work_buf, line_buf, sizeof(work_buf)); // '?'より前をカット cut_before_character(work_buf, '?' ); while ( 1 ){ memset(split1, 0, sizeof(split1)); memset(split2, 0, sizeof(split2)); // 最初に登場する'&'で分割 ret = sentence_split(work_buf, '&', split1, split2 ); if ( ret == 0 ){ // 分割成功 strncpy(work_buf, split2, sizeof(work_buf)); }else if (strlen(work_buf) > 0){ // まだwork_bufに中身ある? strncpy( split1, work_buf, sizeof(split1)); strncpy( work_buf, "", sizeof(work_buf)); }else{ // 処理終了 break; } // ------------------------------------- // GETした内容 解析開始 // 超安直。いいのかこんな比較で。 // ------------------------------------- // URIデコード uri_decode(work_buf2, sizeof(work_buf2), split1, sizeof(split1) ); // "action="あるか調査。 if (strncasecmp( work_buf2, "action=", strlen("action=") ) == 0 ){ // = より前を削除 cut_before_character(work_buf2, '='); // 構造体に値を保存。 strncpy(http_recv_info_p->action, work_buf2, sizeof(http_recv_info_p->action)); continue; } } } debug_log_output("http_recv_info_p->action = '%s'", http_recv_info_p->action); // URIデコード cut_after_character(line_buf, '?'); uri_decode(work_buf, sizeof(work_buf), line_buf, sizeof(line_buf) ); strncpy(line_buf, work_buf, sizeof(line_buf)); debug_log_output("URI(decoded):'%s'\n", line_buf); convert_language_code(line_buf, work_buf, sizeof(work_buf), CODE_AUTO, CODE_EUC); debug_log_output("URI(decoded,euc,FYI):'%s'\n", work_buf); // 構造体に保存 strncpy(http_recv_info_p->recv_uri, line_buf, sizeof(http_recv_info_p->recv_uri)); //httpから始まってる場合には、http://以降の最初の'/'の前でカット if( strncmp(http_recv_info_p->recv_uri,"http://",7)==0){ char* ptr = strstr(http_recv_info_p->recv_uri+7,"/"); if( ptr ){ strcpy(http_recv_info_p->recv_uri,ptr); } } continue; } // User-agent切り出し if ( strncasecmp(line_buf, HTTP_USER_AGENT, strlen(HTTP_USER_AGENT) ) == 0 ){ debug_log_output("User-agent: Detect.\n"); // ':'より前を切る cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); // 構造体に保存 strncpy( http_recv_info_p->user_agent, line_buf, sizeof(http_recv_info_p->user_agent)); continue; } // Rangeあるかチェック if ( strncasecmp(line_buf, HTTP_RANGE, strlen(HTTP_RANGE) ) == 0 ){ debug_log_output("%s Detect.\n", HTTP_RANGE); // ':' より前を切る。 cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); // recv_range にRangeの中身保存 strncpy(http_recv_info_p->recv_range, line_buf, sizeof(http_recv_info_p->recv_range)); // '=' より前を切る cut_before_character(line_buf, '='); // '-'で前後に分割。 sentence_split(line_buf, '-', work_buf, work_buf2); debug_log_output("wrok_buf='%s'\n", work_buf); debug_log_output("wrok_buf2='%s'\n", work_buf2); // 値を文字列→数値変換 http_recv_info_p->range_start_pos = strtoull(work_buf, NULL, 10); if ( strlen(work_buf2) > 0 ){ http_recv_info_p->range_end_pos = strtoull(work_buf2, NULL, 10); } debug_log_output("range_start_pos=%d\n", http_recv_info_p->range_start_pos); debug_log_output("range_end_pos=%d\n", http_recv_info_p->range_end_pos); continue; } // Hostあるかチェック if ( strncasecmp(line_buf, HTTP_HOST, strlen(HTTP_HOST) ) == 0 ){ // ':' より前を切る。 cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); strncpy(http_recv_info_p->recv_host, line_buf, sizeof(http_recv_info_p->recv_host)); debug_log_output("%s Detect. %s '%s'", HTTP_HOST, HTTP_HOST, http_recv_info_p->recv_host); continue; } // Content-Lengthあるかチェック if ( strncasecmp(line_buf, HTTP_CONTENT_LENGTH1, strlen(HTTP_CONTENT_LENGTH1) ) == 0 ){ // ':' より前を切る。 cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); strncpy(http_recv_info_p->content_length, line_buf, sizeof(http_recv_info_p->content_length)); debug_log_output("%s Detect. %s '%s'", HTTP_CONTENT_LENGTH1, HTTP_CONTENT_LENGTH1, http_recv_info_p->content_length); continue; } // Content-TYPEあるかチェック if ( strncasecmp(line_buf, HTTP_CONTENT_TYPE1, strlen(HTTP_CONTENT_TYPE1) ) == 0 ){ // ':' より前を切る。 cut_before_character(line_buf, ':'); cut_first_character(line_buf, ' '); strncpy(http_recv_info_p->content_type, line_buf, sizeof(http_recv_info_p->content_type)); debug_log_output("%s Detect. %s '%s'", HTTP_CONTENT_TYPE1, HTTP_CONTENT_TYPE1, http_recv_info_p->content_type); continue; } } return result; }