📄 http.c
字号:
debug("gwlib.http",0,"Failed while sending request"); goto error; } break; case reading_status: ret = client_read_status(trans); if (ret < 0) { /* * Couldn't read the status from the socket. This may mean * that the socket had been closed by the server after an * idle timeout, so we close the connection and try again, * opening a new socket, but only once. */ if (trans->retrying) { debug("gwlib.http",0,"Failed while retrying"); goto error; } else { /* implicit conn_unregister */ conn_destroy(trans->conn); trans->conn = NULL; trans->retrying = 1; trans->state = request_not_sent; list_produce(pending_requests, trans); return; } } else if (ret == 0) { /* Got the status, go read headers and body next. */ trans->state = reading_entity; trans->response = entity_create(response_expectation(trans->method, trans->status)); } else return; break; case reading_entity: ret = entity_read(trans->response, conn); if (ret < 0) { debug("gwlib.http",0,"Failed reading entity"); goto error; } else if (ret == 0 && http_status_class(trans->status) == HTTP_STATUS_PROVISIONAL) { /* This was a provisional reply; get the real one now. */ trans->state = reading_status; entity_destroy(trans->response); trans->response = NULL; } else if (ret == 0) { trans->state = transaction_done;#ifdef DUMP_RESPONSE /* Dump the response */ debug("wsp.http", 0, "HTTP: Received response:"); h = build_response(trans->response->headers, trans->response->body); octstr_dump(h, 0); octstr_destroy(h);#endif } else { return; } break; default: panic(0, "Internal error: Invalid HTTPServer state."); } } conn_unregister(trans->conn); h = http_header_find_first(trans->response->headers, "Connection"); if (h != NULL && octstr_compare(h, octstr_imm("close")) == 0) trans->persistent = 0; octstr_destroy(h);#ifdef USE_KEEPALIVE if (trans->persistent) { if (proxy_used_for_host(trans->host)) conn_pool_put(trans->conn, proxy_hostname, proxy_port); else conn_pool_put(trans->conn, trans->host, trans->port); } else#endif conn_destroy(trans->conn); trans->conn = NULL; /* * Check if the HTTP server told us to look somewhere else, * hence if we got one of the following response codes: * HTTP_MOVED_PERMANENTLY (301) * HTTP_FOUND (302) * HTTP_SEE_OTHER (303) * HTTP_TEMPORARY_REDIRECT (307) */ if ((h = get_redirection_location(trans)) != NULL) { /* * This is a redirected response, we have to follow. * Clean up all trans stuff for the next request we do. */ octstr_strip_blanks(h); octstr_destroy(trans->url); octstr_destroy(trans->host); trans->port = 0; octstr_destroy(trans->uri); octstr_destroy(trans->username); octstr_destroy(trans->password); trans->host = NULL; trans->port = 0; trans->uri = NULL; trans->username = NULL; trans->password = NULL; trans->ssl = 0; trans->url = h; /* apply new absolute URL to next request */ trans->state = request_not_sent; trans->status = -1; http_destroy_headers(trans->response->headers); trans->response->headers = list_create(); octstr_destroy(trans->response->body); trans->response->body = octstr_create(""); --trans->follow_remaining; conn_destroy(trans->conn); trans->conn = NULL; /* re-inject request to queue */ list_produce(pending_requests, trans); } else { /* handle this response as usual */ list_produce(trans->caller, trans); } return;error: conn_destroy(trans->conn); trans->conn = NULL; error(0, "Couldn't fetch <%s>", octstr_get_cstr(trans->url)); trans->status = -1; list_produce(trans->caller, trans);}/* * Build a complete HTTP request given the host, port, path and headers. * Add Host: and Content-Length: headers (and others that may be necessary). * Return the request as an Octstr. */static Octstr *build_request(char *method_name, Octstr *path_or_url, Octstr *host, long port, List *headers, Octstr *request_body){ /* XXX headers missing */ Octstr *request; int i; request = octstr_format("%s %S HTTP/1.1\r\n", method_name, path_or_url); octstr_format_append(request, "Host: %S", host); if (port != HTTP_PORT) octstr_format_append(request, ":%ld", port); octstr_append(request, octstr_imm("\r\n")); for (i = 0; headers != NULL && i < list_len(headers); ++i) { octstr_append(request, list_get(headers, i)); octstr_append(request, octstr_imm("\r\n")); } octstr_append(request, octstr_imm("\r\n")); if (request_body != NULL) octstr_append(request, request_body); return request;}/* * Re-build the HTTP response given the headers and the body. * Return the response as an Octstr. */static Octstr *build_response(List *headers, Octstr *body){ Octstr *response; int i; response = octstr_create(""); for (i = 0; headers != NULL && i < list_len(headers); ++i) { octstr_append(response, list_get(headers, i)); octstr_append(response, octstr_imm("\r\n")); } octstr_append(response, octstr_imm("\r\n")); if (body != NULL) octstr_append(response, body); return response;}HTTPURLParse *http_urlparse_create(void){ HTTPURLParse *p; p = gw_malloc(sizeof(HTTPURLParse)); p->url = NULL; p->scheme = NULL; p->host = NULL; p->port = 0; p->user = NULL; p->pass = NULL; p->path = NULL; p->query = NULL; p->fragment = NULL; return p;}void http_urlparse_destroy(HTTPURLParse *p){ gw_assert(p != NULL); octstr_destroy(p->url); octstr_destroy(p->scheme); octstr_destroy(p->host); octstr_destroy(p->user); octstr_destroy(p->pass); octstr_destroy(p->path); octstr_destroy(p->query); octstr_destroy(p->fragment); gw_free(p);}void parse_dump(HTTPURLParse *p) { if (p == NULL) return; debug("http.parse_url",0,"Parsing URL `%s':", octstr_get_cstr(p->url)); debug("http.parse_url",0," Scheme: %s", octstr_get_cstr(p->scheme)); debug("http.parse_url",0," Host: %s", octstr_get_cstr(p->host)); debug("http.parse_url",0," Port: %ld", p->port); debug("http.parse_url",0," Username: %s", octstr_get_cstr(p->user)); debug("http.parse_url",0," Password: %s", octstr_get_cstr(p->pass)); debug("http.parse_url",0," Path: %s", octstr_get_cstr(p->path)); debug("http.parse_url",0," Query: %s", octstr_get_cstr(p->query)); debug("http.parse_url",0," Fragment: %s", octstr_get_cstr(p->fragment)); }/* * Parse the URL to get all components, which are: scheme, hostname, * port, username, password, path (URI), query (the CGI parameter list), * fragment (#). * * On success return the HTTPURLParse structure, otherwise NULL if the URL * seems malformed. * * We assume HTTP URLs of the form specified in "3.2.2 http URL" in * RFC 2616: * * http_URL = "http:" "//" [ userid : password "@"] host [ ":" port ] [ abs_path [ "?" query ]] */HTTPURLParse *parse_url(Octstr *url){ HTTPURLParse *p; Octstr *prefix, *prefix_https; long prefix_len; int host_len, colon, slash, at, auth_sep, query; host_len = colon = slash = at = auth_sep = query = 0; prefix = octstr_imm("http://"); prefix_https = octstr_imm("https://"); prefix_len = octstr_len(prefix); if (octstr_case_search(url, prefix, 0) != 0) { if (octstr_case_search(url, prefix_https, 0) == 0) {#ifdef HAVE_LIBSSL debug("gwlib.http", 0, "HTTPS URL; Using SSL for the connection"); prefix = prefix_https; prefix_len = octstr_len(prefix_https); #else error(0, "Attempt to use HTTPS <%s> but SSL not compiled in", octstr_get_cstr(url)); return NULL;#endif } else { error(0, "URL <%s> doesn't start with `%s' nor `%s'", octstr_get_cstr(url), octstr_get_cstr(prefix), octstr_get_cstr(prefix_https)); return NULL; } } /* an URL should be more (at least one charset) then the scheme itself */ if (octstr_len(url) == prefix_len) { error(0, "URL <%s> is malformed.", octstr_get_cstr(url)); return NULL; } /* check if colon and slashes are within scheme */ colon = octstr_search_char(url, ':', prefix_len); slash = octstr_search_char(url, '/', prefix_len); if (colon == prefix_len || slash == prefix_len) { error(0, "URL <%s> is malformed.", octstr_get_cstr(url)); return NULL; } /* create struct and add values succesively while parsing */ p = http_urlparse_create(); p->url = octstr_duplicate(url); p->scheme = octstr_duplicate(prefix); /* try to parse authentication separator */ at = octstr_search_char(url, '@', prefix_len); if (at != -1) { if ((slash == -1 || ( slash != -1 && at < slash))) { auth_sep = octstr_search_char(url, ':', prefix_len); if (auth_sep != -1 && (auth_sep < at)) { octstr_set_char(url, auth_sep, '@'); colon = octstr_search_char(url, ':', prefix_len); } } else { at = -1; } } /* * We have to watch out here for 4 cases: * a) hostname, no port or path * b) hostname, port, no path * c) hostname, path, no port * d) hostname, port and path */ /* we only have the hostname, no port or path. */ if (slash == -1 && colon == -1) { host_len = octstr_len(url) - prefix_len;#ifdef HAVE_LIBSSL p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ? HTTPS_PORT : HTTP_PORT;#else p->port = HTTP_PORT;#endif /* HAVE_LIBSSL */ } /* we have a port, but no path. */ else if (slash == -1) { host_len = colon - prefix_len; if (octstr_parse_long(&(p->port), url, colon + 1, 10) == -1) { error(0, "URL <%s> has malformed port number.", octstr_get_cstr(url)); http_urlparse_destroy(p); return NULL; } } /* we have a path, but no port. */ else if (colon == -1 || colon > slash) { host_len = slash - prefix_len;#ifdef HAVE_LIBSSL p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ? HTTPS_PORT : HTTP_PORT;#else p->port = HTTP_PORT;#endif /* HAVE_LIBSSL */ } /* we have both, path and port. */ else if (colon < slash) { host_len = colon - prefix_len; if (octstr_parse_long(&(p->port), url, colon + 1, 10) == -1) { error(0, "URL <%s> has malformed port number.", octstr_get_cstr(url)); http_urlparse_destroy(p); return NULL; } /* none of the above, so there is something wrong here */ } else { error(0, "Internal error in URL parsing logic."); http_urlparse_destroy(p); return NULL; } /* there was an authenticator separator, so try to parse * the username and password credentials */ if (at != -1) { int at2; at2 = octstr_search_char(url, '@', prefix_len); p->user = octstr_copy(url, prefix_len, at2 - prefix_len); p->pass = (at2 != at) ? octstr_copy(url, at2 + 1, at - at2 - 1) : NULL; if (auth_sep != -1) octstr_set_char(url, auth_sep, ':'); host_len = host_len - at + prefix_len - 1; prefix_len = at + 1; } /* query (CGI vars) */ query = octstr_search_char(url, '?', (slash == -1) ? prefix_len : slash); if (query != -1) { p->query = octstr_copy(url, query + 1, octstr_len(url)); } /* path */ p->path = (slash == -1) ? octstr_create("/") : ((query != -1) && (query > slash) ? octstr_copy(url, slash, query - slash) : octstr_copy(url, slash, octstr_len(url) - slash)); /* hostname */ p->host = octstr_copy(url, prefix_len, (query == -1 || slash != -1) ? host_len : query - prefix_len); /* XXX add fragment too */ /* dump components */ parse_dump(p); return p;}/* copy all relevant parsed data to the server info struct */static void parse2trans(HTTPURLParse *p, HTTPServer *t){ if (p == NULL || t == NULL) return; if (p->user && !t->username) t->username = octstr_duplicate(p->user); if (p->pass && !t->password) t->password = octstr_duplicate(p->pass); if (p->host && !t->host) t->host = octstr_duplicate(p->host); if (p->port && !t->port) t->port = p->port; if (p->path && !t->uri) { t->uri = octstr_duplicate(p->path); if (p->query) { /* add the query too */ octstr_append_char(t->uri, '?'); octstr_append(t->uri, p->query); } } t->ssl = (p->scheme && (octstr_compare(p->scheme, octstr_imm("https://")) == 0) && !t->ssl) ? 1 : 0;}static Connection *get_connection(HTTPServer *trans) { Connection *conn; Octstr *host; HTTPURLParse *p; int port; conn = NULL; /* if the parsing has not yet been done, then do it now */ if (!trans->host && trans->port == 0 && trans->url != NULL) { if ((p = parse_url(trans->url)) != NULL) { parse2trans(p, trans); http_urlparse_destroy(p); } else { goto error; } } if (proxy_used_for_host(trans->host)) { host = proxy_hostname; port = proxy_port; } else { host = trans->host; port = trans->port; } if (trans->retrying) {#ifdef HAVE_LIBSSL if (trans->ssl) conn = conn_open_ssl(host, port, trans->certkeyfile, http_interface); else#endif /* HAVE_LIBSSL */ conn = conn_open_tcp_nb(host, port, http_interface); debug("gwlib.http", 0, "HTTP: Opening NEW connection to `%s:%d' (fd=%d).", octstr_get_cstr(host), port, conn_get_id(conn)); } else conn = conn_pool_get(host, port, trans->ssl, trans->certkeyfile, http_interface); if (conn == NULL) goto error; return conn;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -