|
|
| version 1.3, 2006/04/09 13:38:47 | version 1.11, 2008/02/22 17:29:38 |
|---|---|
| Line 19 static const char * const IDENT_HTTP_C=" | Line 19 static const char * const IDENT_HTTP_C=" |
| #define HTTP_BODY_NAME "body" | #define HTTP_BODY_NAME "body" |
| #define HTTP_TIMEOUT_NAME "timeout" | #define HTTP_TIMEOUT_NAME "timeout" |
| #define HTTP_HEADERS_NAME "headers" | #define HTTP_HEADERS_NAME "headers" |
| #define HTTP_COOKIES_NAME "cookies" | |
| #define HTTP_ANY_STATUS_NAME "any-status" | #define HTTP_ANY_STATUS_NAME "any-status" |
| #define HTTP_CHARSET_NAME "charset" | // #define HTTP_CHARSET_NAME "charset" |
| #define HTTP_TABLES_NAME "tables" | #define HTTP_TABLES_NAME "tables" |
| #define HTTP_USER "user" | #define HTTP_USER "user" |
| #define HTTP_PASSWORD "password" | #define HTTP_PASSWORD "password" |
| Line 285 struct Http_pass_header_info { | Line 286 struct Http_pass_header_info { |
| bool user_agent_specified; | bool user_agent_specified; |
| }; | }; |
| #endif | #endif |
| static void http_pass_header(HashStringValue::key_type key, | static void http_pass_header(HashStringValue::key_type name, |
| HashStringValue::value_type value, | HashStringValue::value_type value, |
| Http_pass_header_info *info) { | Http_pass_header_info *info) { |
| *info->request <<key<<": " | |
| << attributed_meaning_to_string(*value, String::L_HTTP_HEADER, false) | String aname=String(name, String::L_URI); |
| << CRLF; | |
| *info->request <<aname<<": " | |
| << attributed_meaning_to_string(*value, String::L_URI, false) | |
| << CRLF; | |
| if(String(key, String::L_TAINTED).change_case(info->charsets->source(), String::CC_UPPER)=="USER-AGENT") | if(aname.change_case(info->charsets->source(), String::CC_UPPER)=="USER-AGENT") |
| info->user_agent_specified=true; | info->user_agent_specified=true; |
| } | } |
| static void http_pass_cookie(HashStringValue::key_type name, | |
| HashStringValue::value_type value, | |
| Http_pass_header_info *info) { | |
| *info->request << String(name, String::L_HTTP_HEADER) << "=" | |
| << attributed_meaning_to_string(*value, String::L_HTTP_HEADER, false) | |
| << "; "; | |
| } | |
| static Charset* detect_charset(Charset& source_charset, const String& content_type_value) { | static Charset* detect_charset(Charset& source_charset, const String& content_type_value) { |
| const String::Body CONTENT_TYPE_VALUE= | const String::Body CONTENT_TYPE_VALUE= |
| Line 305 static Charset* detect_charset(Charset& | Line 318 static Charset* detect_charset(Charset& |
| // content-type: xxx/xxx; source_charset="WE-NEED-THIS"; | // content-type: xxx/xxx; source_charset="WE-NEED-THIS"; |
| size_t before_charseteq_pos=CONTENT_TYPE_VALUE.pos("CHARSET="); | size_t before_charseteq_pos=CONTENT_TYPE_VALUE.pos("CHARSET="); |
| if(before_charseteq_pos!=STRING_NOT_FOUND) { | if(before_charseteq_pos!=STRING_NOT_FOUND) { |
| size_t charset_begin=before_charseteq_pos+8/*CHARSET="*/; | size_t charset_begin=before_charseteq_pos+8/*CHARSET=*/; |
| size_t open_quote_pos=CONTENT_TYPE_VALUE.pos('"', charset_begin); | size_t open_quote_pos=CONTENT_TYPE_VALUE.pos('"', charset_begin); |
| bool quoted=open_quote_pos==charset_begin; | bool quoted=open_quote_pos==charset_begin; |
| if(quoted) | if(quoted) |
| Line 321 static Charset* detect_charset(Charset& | Line 334 static Charset* detect_charset(Charset& |
| charset_end=delim_pos; | charset_end=delim_pos; |
| } | } |
| const String::Body CHARSET_NAME_BODY= | const String::Body CHARSET_NAME_BODY= |
| CONTENT_TYPE_VALUE.mid(charset_begin, charset_end); | CONTENT_TYPE_VALUE.mid(charset_begin, charset_end - charset_begin); |
| return &charsets.get(CHARSET_NAME_BODY); | return &charsets.get(CHARSET_NAME_BODY); |
| } | } |
| Line 380 static void form_value2string( | Line 393 static void form_value2string( |
| new String(key, String::L_TAINTED), | new String(key, String::L_TAINTED), |
| "is %s, "HTTP_FORM_NAME" option value must either string or table", value->type()); | "is %s, "HTTP_FORM_NAME" option value must either string or table", value->type()); |
| } | } |
| const char* pa_form2string(HashStringValue& form) { | const char* pa_form2string(HashStringValue& form, Request_charsets& charsets) { |
| String string; | String string; |
| form.for_each<String*>(form_value2string, &string); | form.for_each<String*>(form_value2string, &string); |
| return string.cstr(String::L_UNSPECIFIED); | return string.cstr(String::L_UNSPECIFIED, 0, &charsets); |
| } | } |
| static void find_headers_end(char* p, | static void find_headers_end(char* p, |
| char*& headers_end_at, | char*& headers_end_at, |
| Line 413 File_read_http_result pa_internal_file_r | Line 426 File_read_http_result pa_internal_file_r |
| char host[MAX_STRING]; | char host[MAX_STRING]; |
| const char* uri; | const char* uri; |
| short port; | short port; |
| const char* method="GET"; bool method_is_get; | const char* method="GET"; |
| HashStringValue* form=0; | HashStringValue* form=0; |
| const char* body_cstr=0; | const char* body_cstr=0; |
| int timeout_secs=2; | int timeout_secs=2; |
| bool fail_on_status_ne_200=true; | bool fail_on_status_ne_200=true; |
| Value* vheaders=0; | Value* vheaders=0; |
| Value* vcookies=0; | |
| Value* vbody=0; | |
| Charset *asked_remote_charset=0; | Charset *asked_remote_charset=0; |
| const char* user_cstr=0; | const char* user_cstr=0; |
| const char* password_cstr=0; | const char* password_cstr=0; |
| Line 434 File_read_http_result pa_internal_file_r | Line 449 File_read_http_result pa_internal_file_r |
| valid_options++; | valid_options++; |
| form=vform->get_hash(); | form=vform->get_hash(); |
| } | } |
| if(Value* vbody=options->get(HTTP_BODY_NAME)) { | if(vbody=options->get(HTTP_BODY_NAME)) { |
| valid_options++; | valid_options++; |
| body_cstr=vbody->as_string().cstr(String::L_UNSPECIFIED); | |
| } | } |
| if(Value* vtimeout=options->get(HTTP_TIMEOUT_NAME)) { | if(Value* vtimeout=options->get(HTTP_TIMEOUT_NAME)) { |
| valid_options++; | valid_options++; |
| timeout_secs=vtimeout->as_int(); | timeout_secs=vtimeout->as_int(); |
| } | } |
| if((vheaders=options->get(HTTP_HEADERS_NAME))) { | if(vheaders=options->get(HTTP_HEADERS_NAME)) { |
| valid_options++; | |
| } | |
| if(vcookies=options->get(HTTP_COOKIES_NAME)) { | |
| valid_options++; | valid_options++; |
| } | } |
| if(Value* vany_status=options->get(HTTP_ANY_STATUS_NAME)) { | if(Value* vany_status=options->get(HTTP_ANY_STATUS_NAME)) { |
| valid_options++; | valid_options++; |
| fail_on_status_ne_200=!vany_status->as_bool(); | fail_on_status_ne_200=!vany_status->as_bool(); |
| } | } |
| if(Value* vcharset_name=options->get(HTTP_CHARSET_NAME)) { | if(Value* vcharset_name=options->get(PA_CHARSET_NAME)) { |
| valid_options++; | |
| asked_remote_charset=&::charsets.get(vcharset_name->as_string(). | asked_remote_charset=&::charsets.get(vcharset_name->as_string(). |
| change_case(charsets.source(), String::CC_UPPER)); | change_case(charsets.source(), String::CC_UPPER)); |
| } | } |
| Line 464 File_read_http_result pa_internal_file_r | Line 480 File_read_http_result pa_internal_file_r |
| } | } |
| if(valid_options!=options->count()) | if(valid_options!=options->count()) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "invalid option passed"); | "invalid option passed"); |
| } | } |
| if(!asked_remote_charset) // defaulting to $request:charset | if(!asked_remote_charset) // defaulting to $request:charset |
| asked_remote_charset=&charsets.source(); | asked_remote_charset=&charsets.source(); |
| method_is_get=strcmp(method, "GET")==0; | bool method_is_get=strcmp(method, "GET")==0; |
| if(method_is_get && body_cstr) | if(vbody){ |
| throw Exception("parser.runtime", | if(method_is_get) |
| 0, | throw Exception(PARSER_RUNTIME, |
| "you can not use $."HTTP_BODY_NAME" option with method GET"); | 0, |
| "you can not use $."HTTP_BODY_NAME" option with method GET"); | |
| if(form) | |
| throw Exception(PARSER_RUNTIME, | |
| 0, | |
| "you can not use options $."HTTP_BODY_NAME" and $."HTTP_FORM_NAME" together"); | |
| } | |
| //preparing request | //preparing request |
| String& connect_string=*new String; | String& connect_string=*new String; |
| Line 487 File_read_http_result pa_internal_file_r | Line 510 File_read_http_result pa_internal_file_r |
| // influence URLencoding of tainted pieces to String::L_URI lang | // influence URLencoding of tainted pieces to String::L_URI lang |
| Temp_client_charset temp(charsets, *asked_remote_charset); | Temp_client_charset temp(charsets, *asked_remote_charset); |
| const char* connect_string_cstr=connect_string.cstr(String::L_UNSPECIFIED); | const char* connect_string_cstr=connect_string.cstr(String::L_UNSPECIFIED, 0, &charsets); |
| const char* current=connect_string_cstr; | const char* current=connect_string_cstr; |
| if(strncmp(current, "http://", 7)!=0) | if(strncmp(current, "http://", 7)!=0) |
| Line 505 File_read_http_result pa_internal_file_r | Line 528 File_read_http_result pa_internal_file_r |
| bool uri_has_query_string=strchr(uri, '?')!=0; | bool uri_has_query_string=strchr(uri, '?')!=0; |
| //making request head | // making request head |
| String head; | String head; |
| head << method; | head << method << " " << uri; |
| head << " " << uri; | if(form && method_is_get) |
| if(form) | head << (uri_has_query_string?"&":"?") << pa_form2string(*form, charsets); |
| if(method_is_get) | |
| head << (uri_has_query_string?"&":"?") << pa_form2string(*form); | head <<" HTTP/1.0" CRLF "host: "<< host << CRLF; |
| head <<" HTTP/1.0" CRLF | |
| "host: "<< host << CRLF; | |
| if(form && !method_is_get) { | if(form && !method_is_get) { |
| head << "content-type: application/x-www-form-urlencoded" CRLF; | head << "content-type: application/x-www-form-urlencoded" CRLF; |
| body_cstr = pa_form2string(*form); | body_cstr=pa_form2string(*form, charsets); |
| } else if (vbody) { | |
| body_cstr=vbody->as_string().cstr(String::L_UNSPECIFIED, 0, &charsets); | |
| // needed for transcoded $.body[] first of all | |
| body_cstr=Charset::transcode( | |
| String::C(body_cstr, strlen(body_cstr)), | |
| charsets.source(), | |
| *asked_remote_charset | |
| ); | |
| } | } |
| // http://www.ietf.org/rfc/rfc2617.txt | // http://www.ietf.org/rfc/rfc2617.txt |
| Line 530 File_read_http_result pa_internal_file_r | Line 560 File_read_http_result pa_internal_file_r |
| headers->for_each<Http_pass_header_info*>(http_pass_header, &info); | headers->for_each<Http_pass_header_info*>(http_pass_header, &info); |
| user_agent_specified=info.user_agent_specified; | user_agent_specified=info.user_agent_specified; |
| } else | } else |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| &connect_string, | &connect_string, |
| "headers param must be hash"); | "headers param must be hash"); |
| }; | }; |
| if(!user_agent_specified) // defaulting | if(!user_agent_specified) // defaulting |
| head << "user-agent: " DEFAULT_USER_AGENT CRLF; | head << "user-agent: " DEFAULT_USER_AGENT CRLF; |
| if(body_cstr) { | if(vcookies && !vcookies->is_string()){ // allow empty |
| // recode those pieces which are not in String::L_URI lang | if(HashStringValue* cookies=vcookies->get_hash()) { |
| // [those violating HTTP standard, but widly used] | head << "cookie: "; |
| body_cstr=Charset::transcode( | Http_pass_header_info info={&charsets, &head, false}; |
| String::C(body_cstr, strlen(body_cstr)), | cookies->for_each<Http_pass_header_info*>(http_pass_cookie, &info); |
| charsets.source(), | head << CRLF; |
| *asked_remote_charset); | } else |
| throw Exception(PARSER_RUNTIME, | |
| &connect_string, | |
| "cookies param must be hash"); | |
| } | |
| if(body_cstr) { | |
| head << "content-length: " << format(strlen(body_cstr), "%u") << CRLF; | head << "content-length: " << format(strlen(body_cstr), "%u") << CRLF; |
| } | } |
| const char* head_cstr=head.cstr(String::L_UNSPECIFIED); | const char* head_cstr=head.cstr(String::L_UNSPECIFIED, 0, &charsets); |
| // recode those pieces which are not in String::L_URI lang | |
| // [those violating HTTP standard, but widly used] | |
| head_cstr=Charset::transcode( | |
| String::C(head_cstr, strlen(head_cstr)), | |
| charsets.source(), | |
| *asked_remote_charset); | |
| // head + end of header | // head + end of header |
| request_head_and_body << head_cstr << CRLF; | request_head_and_body << head_cstr << CRLF; |
| // body | // body |
| if(body_cstr) | if(body_cstr) |
| request_head_and_body << body_cstr; | request_head_and_body << body_cstr; |