|
|
| version 1.8, 2008/02/14 18:31:38 | version 1.12, 2008/06/06 13:04:45 |
|---|---|
| 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_OMIT_POST_CHARSET "omit-post-charset" // ^file::load[...;http://...;$.form[...]$.method[post]] |
| // by default add charset to content-type | |
| #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 283 struct Http_pass_header_info { | Line 287 struct Http_pass_header_info { |
| Request_charsets* charsets; | Request_charsets* charsets; |
| String* request; | String* request; |
| bool user_agent_specified; | bool user_agent_specified; |
| bool content_type_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") | const String::Body name_upper=aname.change_case(info->charsets->source(), String::CC_UPPER); |
| info->user_agent_specified=true; | if(name_upper==HTTP_USER_AGENT) |
| info->user_agent_specified=true; | |
| if(name_upper==HTTP_CONTENT_TYPE) | |
| info->content_type_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 413 File_read_http_result pa_internal_file_r | Line 433 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; |
| bool omit_post_charset=false; | |
| 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 457 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* vomit_post_charset=options->get(HTTP_OMIT_POST_CHARSET)){ | |
| valid_options++; | |
| omit_post_charset=vomit_post_charset->as_bool(); | |
| } | |
| if(Value* vcharset_name=options->get(PA_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 471 File_read_http_result pa_internal_file_r | Line 499 File_read_http_result pa_internal_file_r |
| 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 505 File_read_http_result pa_internal_file_r | Line 540 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, charsets); | head <<" HTTP/1.0" CRLF "host: "<< host << CRLF; |
| head <<" HTTP/1.0" CRLF | |
| "host: "<< host << CRLF; | if(form && !method_is_get) { // POST |
| if(form && !method_is_get) { | head << "content-type: " << HTTP_CONTENT_TYPE_FORM_URLENCODED; |
| head << "content-type: application/x-www-form-urlencoded" CRLF; | if(!omit_post_charset) |
| body_cstr = pa_form2string(*form, charsets); | head << "; charset=" << asked_remote_charset->NAME_CSTR() << ";"; |
| head << CRLF; | |
| 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 524 File_read_http_result pa_internal_file_r | Line 569 File_read_http_result pa_internal_file_r |
| head<<"authorization: "<<*authorization_field_value<<CRLF; | head<<"authorization: "<<*authorization_field_value<<CRLF; |
| bool user_agent_specified=false; | bool user_agent_specified=false; |
| bool content_type_specified=false; | |
| if(vheaders && !vheaders->is_string()) { // allow empty | if(vheaders && !vheaders->is_string()) { // allow empty |
| if(HashStringValue *headers=vheaders->get_hash()) { | if(HashStringValue *headers=vheaders->get_hash()) { |
| Http_pass_header_info info={&charsets, &head, false}; | Http_pass_header_info info={&charsets, &head, false}; |
| 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; |
| content_type_specified=info.content_type_specified; | |
| } else | } else |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, |
| &connect_string, | &connect_string, |
| Line 537 File_read_http_result pa_internal_file_r | Line 584 File_read_http_result pa_internal_file_r |
| 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(form && !method_is_get && content_type_specified) // POST + form + content-type was specified | |
| throw Exception(PARSER_RUNTIME, | |
| &connect_string, | |
| "$.content-type can't be specified with method POST"); | |
| if(vcookies && !vcookies->is_string()){ // allow empty | |
| if(HashStringValue* cookies=vcookies->get_hash()) { | |
| head << "cookie: "; | |
| Http_pass_header_info info={&charsets, &head, false}; | |
| cookies->for_each<Http_pass_header_info*>(http_pass_cookie, &info); | |
| head << CRLF; | |
| } else | |
| throw Exception(PARSER_RUNTIME, | |
| &connect_string, | |
| "cookies param must be hash"); | |
| } | |
| if(body_cstr) { | if(body_cstr) { |
| head << "content-length: " << format(strlen(body_cstr), "%u") << CRLF; | head << "content-length: " << format(strlen(body_cstr), "%u") << CRLF; |
| } | } |
| Line 593 File_read_http_result pa_internal_file_r | Line 657 File_read_http_result pa_internal_file_r |
| const String::Body HEADER_NAME= | const String::Body HEADER_NAME= |
| line.mid(0, pos).change_case(charsets.source(), String::CC_UPPER); | line.mid(0, pos).change_case(charsets.source(), String::CC_UPPER); |
| const String& header_value=line.mid(pos+1, line.length()).trim(String::TRIM_BOTH, " \t\r"); | const String& header_value=line.mid(pos+1, line.length()).trim(String::TRIM_BOTH, " \t\r"); |
| if(as_text && HEADER_NAME=="CONTENT-TYPE") | if(as_text && HEADER_NAME==HTTP_CONTENT_TYPE) |
| real_remote_charset=detect_charset(charsets.source(), header_value); | real_remote_charset=detect_charset(charsets.source(), header_value); |
| // tables | // tables |