📄 http.c
字号:
* Don't redirect POST content without approval * from an interactive user. - FM */ HTTP_NETCLOSE(s, handle); status = -1; HTAlert( gettext("Redirection of POST content requires user approval.")); if (traversal) HTProgress(line_buffer); goto clean_up; } HTProgress(line_buffer); if (server_status == 301) { /* Moved Permanently */ if (do_post) { /* * Don't make the redirection permanent * if we have POST content. - FM */ CTRACE((tfp, "HTTP: Have POST content. Treating 301 (Permanent) as Temporary.\n")); HTAlert( gettext("Have POST content. Treating Permanent Redirection as Temporary.\n")); } else { permanent_redirection = TRUE; } } doing_redirect = TRUE; break; } case 4: /* ** "I think I goofed!" (Client Error) - FM */ switch (server_status) { case 401: /* Unauthorized */ /* * Authorization for orgin server required. * If show_401 is set, proceed to showing the * 401 body. Otherwise, if we can set up * authorization based on the WWW-Authenticate * header, and the user provides a username and * password, try again. Otherwise, check whether * to show the 401 body or restore the current * document. - FM */ if (show_401) break; if (HTAA_shouldRetryWithAuth(start_of_data, length, s, NO)) { HTTP_NETCLOSE(s, handle); if (dump_output_immediately && !authentication_info[0]) { fprintf(stderr, "HTTP: Access authorization required.\n"); fprintf(stderr, " Use the -auth=id:pw parameter.\n"); status = HT_NO_DATA; goto clean_up; } CTRACE((tfp, "%s %d %s\n", "HTTP: close socket", s, "to retry with Access Authorization")); _HTProgress ( gettext("Retrying with access authorization information.")); FREE(line_buffer); FREE(line_kept_clean);#ifdef USE_SSL if (using_proxy && !strncmp(url, "https://", 8)) { url = arg; do_connect = TRUE; did_connect = FALSE; }#endif /* USE_SSL */ goto try_again; } else if (!(traversal || dump_output_immediately) && HTConfirm(gettext("Show the 401 message body?"))) { break; } else { if (traversal || dump_output_immediately) HTAlert(FAILED_RETRY_WITH_AUTH); HTTP_NETCLOSE(s, handle); status = -1; goto clean_up; } case 407: /* * Authorization for proxy server required. * If we are not in fact using a proxy, or * show_407 is set, proceed to showing the * 407 body. Otherwise, if we can set up * authorization based on the Proxy-Authenticate * header, and the user provides a username and * password, try again. Otherwise, check whether * to show the 401 body or restore the current * document. - FM & AJL */ if (!using_proxy || show_407) break; if (HTAA_shouldRetryWithAuth(start_of_data, length, s, YES)) { HTTP_NETCLOSE(s, handle); if (dump_output_immediately && !proxyauth_info[0]) { fprintf(stderr, "HTTP: Proxy authorization required.\n"); fprintf(stderr, " Use the -pauth=id:pw parameter.\n"); status = HT_NO_DATA; goto clean_up; } CTRACE((tfp, "%s %d %s\n", "HTTP: close socket", s, "to retry with Proxy Authorization")); _HTProgress (HTTP_RETRY_WITH_PROXY); FREE(line_buffer); FREE(line_kept_clean); goto try_again; } else if (!(traversal || dump_output_immediately) && HTConfirm(gettext("Show the 407 message body?"))) { if (!dump_output_immediately && format_out == HTAtom_for("www/download")) { /* * Convert a download request to * a presentation request for * interactive users. - FM */ format_out = WWW_PRESENT; } break; } else { if (traversal || dump_output_immediately) HTAlert(FAILED_RETRY_WITH_PROXY); HTTP_NETCLOSE(s, handle); status = -1; goto clean_up; } case 408: /* * Request Timeout. Show the status message * and restore the current document. - FM */ HTAlert(line_buffer); HTTP_NETCLOSE(s, handle); status = HT_NO_DATA; goto done; default: /* * 400 Bad Request. * 402 Payment Required. * 403 Forbidden. * 404 Not Found. * 405 Method Not Allowed. * 406 Not Acceptable. * 409 Conflict. * 410 Gone. * 411 Length Required. * 412 Precondition Failed. * 413 Request Entity Too Large. * 414 Request-URI Too Long. * 415 Unsupported Media Type. * 416 List Response (for content negotiation). * > 416 is unknown. * Show the status message, and display * the returned text if we are not doing * a traversal. - FM */ HTAlert(line_buffer); if (traversal) { HTTP_NETCLOSE(s, handle); status = -1; goto clean_up; } if (!dump_output_immediately && format_out == HTAtom_for("www/download")) { /* * Convert a download request to * a presentation request for * interactive users. - FM */ format_out = WWW_PRESENT; } break; } /* case 4 switch */ break; case 5: /* ** "I think YOU goofed!" (server error) ** 500 Internal Server Error ** 501 Not Implemented ** 502 Bad Gateway ** 503 Service Unavailable ** 504 Gateway Timeout ** 505 HTTP Version Not Supported ** > 505 is unknown. ** Should always include a message, which ** we always should display. - FM */ HTAlert(line_buffer); if (traversal) { HTTP_NETCLOSE(s, handle); status = -1; goto clean_up; } if (!dump_output_immediately && format_out == HTAtom_for("www/download")) { /* * Convert a download request to * a presentation request for * interactive users. - FM */ format_out = WWW_PRESENT; } break; default: /* ** Bad or unknown server_status number. ** Take a chance and hope there is ** something to display. - FM */ HTAlert(gettext("Unknown status reply from server!")); HTAlert(line_buffer); if (traversal) { HTTP_NETCLOSE(s, handle); status = -1; goto clean_up; } if (!dump_output_immediately && format_out == HTAtom_for("www/download")) { /* * Convert a download request to * a presentation request for * interactive users. - FM */ format_out = WWW_PRESENT; } break; } /* Switch on server_status/100 */ } /* Full HTTP reply */ } /* scope of fields */ /* ** The user may have pressed the 'z'ap key during the pause caused ** by one of the HTAlerts above if the server reported an error, ** to skip loading of the error response page. Checking here before ** setting up the stream stack and feeding it data avoids doing ** unnecessary work, it also can avoid unnecessarily pushing a ** loaded document out of the cache to make room for the unwanted ** error page. - kw */ if (HTCheckForInterrupt()) { HTTP_NETCLOSE(s, handle); if (doing_redirect) { /* * Impatient user. - FM */ CTRACE((tfp, "HTTP: Interrupted followup read.\n")); _HTProgress (CONNECTION_INTERRUPTED); } status = HT_INTERRUPTED; goto clean_up; } /* ** Set up the stream stack to handle the body of the message. */ if (do_head || keep_mime_headers) { /* ** It was a HEAD request, or we want the headers and source. */ start_of_data = line_kept_clean;#ifdef SH_EX /* FIX BUG by kaz@maczuka.hitachi.ibaraki.jp *//* GIF file contains \0, so strlen does not return the data length */ length = real_length_of_line;#else length = rawlength;#endif format_in = HTAtom_for("text/plain"); } else if (doing_redirect) { format_in = HTAtom_for("message/x-http-redirection"); StrAllocCopy(anAnchor->content_type, HTAtom_name(format_in)); if (traversal) { format_out = WWW_DEBUG; if (!sink) sink = HTErrorStream(); } else if (!dump_output_immediately && format_out == HTAtom_for("www/download")) { /* * Convert a download request to * a presentation request for * interactive users. - FM */ format_out = WWW_PRESENT; } } target = HTStreamStack(format_in, format_out, sink, anAnchor); if (!target || target == NULL) { char *buffer = NULL; HTTP_NETCLOSE(s, handle); HTSprintf0(&buffer, CANNOT_CONVERT_I_TO_O, HTAtom_name(format_in), HTAtom_name(format_out)); _HTProgress (buffer); FREE(buffer); status = -1; goto clean_up; } /* ** Recycle the first chunk of data, in all cases. */ (*target->isa->put_block)(target, start_of_data, length); /* ** Go pull the bulk of the data down. */ rv = HTCopy(anAnchor, s, (void *)handle, target); /* ** If we get here with doing_redirect set, it means that we were ** looking for a Location header. We either have got it now in ** redirecting_url - in that case the stream should not have loaded ** any data. Or we didn't get it, in that case the stream may have ** presented the message body normally. - kw */ if (rv == -1) { /* ** Intentional interrupt before data were received, not an error */ /* (*target->isa->_abort)(target, NULL); */ /* already done in HTCopy */ if (doing_redirect && traversal) status = -1; else status = HT_INTERRUPTED; HTTP_NETCLOSE(s, handle); goto clean_up; } if (rv == -2) { /* ** Aw hell, a REAL error, maybe cuz it's a dumb HTTP0 server */ (*target->isa->_abort)(target, NULL); if (doing_redirect && redirecting_url) { /* ** Got a location before the error occurred? Then consider it ** an interrupt but proceed below as normal. - kw */ /* do nothing here */ } else { HTTP_NETCLOSE(s, handle); if (!doing_redirect && !already_retrying && !do_post) { CTRACE((tfp, "HTTP: Trying again with HTTP0 request.\n")); /* ** May as well consider it an interrupt -- right? */ FREE(line_buffer); FREE(line_kept_clean); extensions = NO; already_retrying = TRUE; _HTProgress (RETRYING_AS_HTTP0); goto try_again; } else { status = HT_NOT_LOADED; goto clean_up; } } } /* ** Free if complete transmission (socket was closed before return). ** Close socket if partial transmission (was freed on abort). */ if (rv != HT_INTERRUPTED && rv != -2) { (*target->isa->_free)(target); } else { HTTP_NETCLOSE(s, handle); } if (doing_redirect) { if (redirecting_url) { /* * Set up for checking redirecting_url in * LYGetFile.c for restrictions before we * seek the document at that Location. - FM */ CTRACE((tfp, "HTTP: Picked up location '%s'\n", redirecting_url)); if (rv == HT_INTERRUPTED) { /* ** Intentional interrupt after data were received, not an ** error (probably). We take it as a user request to ** abandon the redirection chain. ** This could reasonably be changed (by just removing this ** block), it would make sense if there are redirecting ** resources that "hang" after sending the headers. - kw */ FREE(redirecting_url); CTRACE((tfp, "HTTP: Interrupted followup read.\n")); status = HT_INTERRUPTED; goto clean_up; } HTProgress(line_buffer); if (server_status == 305) { /* Use Proxy */ /* * Make sure the proxy field ends with * a slash. - FM */ if (redirecting_url[strlen(redirecting_url)-1] != '/') StrAllocCat(redirecting_url, "/"); /* * Append our URL. - FM */ StrAllocCat(redirecting_url, anAnchor->address); CTRACE((tfp, "HTTP: Proxy URL is '%s'\n", redirecting_url)); } if (!do_post || server_status == 303 || server_status == 302) { /* * We don't have POST content (nor support PUT * or DELETE), or the status is "See Other" or * "General Redirection" and we can convert to * GET, so go back and check out the new URL. - FM */ status = HT_REDIRECTING; goto clean_up; } /* * Make sure the user wants to redirect * the POST content, or treat as GET - FM & DK */ switch (HTConfirmPostRedirect(redirecting_url, server_status)) { /* * User failed to confirm. * Abort the fetch. */ case 0: doing_redirect = FALSE; FREE(redirecting_url); status = HT_NO_DATA; goto clean_up; /* * User wants to treat as GET with no content. * Go back to check out the URL. */ case 303: break; /* * Set the flag to retain the POST * content and go back to check out * the URL. - FM */ default: redirect_post_content = TRUE; } /* Lou's old comment: - FM */ /* OK, now we've got the redirection URL temporarily stored in external variable redirecting_url, exported from HTMIME.c, since there's no straightforward way to do this in the library currently. Do the right thing. */ status = HT_REDIRECTING; } else { status = traversal ? -1 : HT_LOADED; } } else { /* ** If any data were received, treat as a complete transmission */ status = HT_LOADED; } /* ** Clean up */clean_up: FREE(line_buffer); FREE(line_kept_clean);done: /* ** Clear out on exit, just in case. */ do_head = FALSE; do_post = FALSE; reloading = FALSE;#ifdef USE_SSL do_connect = FALSE; did_connect = FALSE; FREE(connect_host); if (handle) { SSL_free(handle); SSL_handle = handle = NULL; }#endif /* USE_SSL */ return status;}/* Protocol descriptor*/#ifdef GLOBALDEF_IS_MACRO#define _HTTP_C_GLOBALDEF_1_INIT { "http", HTLoadHTTP, 0}GLOBALDEF (HTProtocol,HTTP,_HTTP_C_GLOBALDEF_1_INIT);#define _HTTP_C_GLOBALDEF_2_INIT { "https", HTLoadHTTP, 0}GLOBALDEF (HTProtocol,HTTPS,_HTTP_C_GLOBALDEF_2_INIT);#elseGLOBALDEF PUBLIC HTProtocol HTTP = { "http", HTLoadHTTP, 0 };GLOBALDEF PUBLIC HTProtocol HTTPS = { "https", HTLoadHTTP, 0 };#endif /* GLOBALDEF_IS_MACRO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -