?? http.c
字號:
case HTTP_SEE_OTHER: /* * Not so fine, but we still have to read the * headers to get the new location. */ break; case HTTP_NEED_AUTH: if (request->need_auth) { /* * We already sent out authorization code, * so there's nothing more we can do. */ _http_seterr(conn->err); return(-1); } /* try again, but send the password this time */ if (request->verbose) _fetch_info("server requires authorization"); break; case HTTP_NEED_PROXY_AUTH: /* * If we're talking to a proxy, we already sent * our proxy authorization code, so there's * nothing more we can do. */ _http_seterr(conn->err); return(-1); case HTTP_BAD_RANGE: /* * This can happen if we ask for 0 bytes because * we already have the whole file. Consider this * a success for now, and check sizes later. */ request->last_read_short = 1; break; case HTTP_PROTOCOL_ERROR: /* fall through */ case -1: /* RMDBGLOG((ENABLE,"Error getting reply : errno = %d\n", errno)); */ _fetch_syserr(); return(-1); default: _http_seterr(conn->err); if (!request->verbose) return (-1); /* fall through so we can get the full error message */ } return(0);}/** * Get headers from a HTTP reply * @param request - the HTTP request * @return < 0 on error */static RMint32 __http_get_headers(struct http_request_s *request){ struct url *url, *purl; conn_t *conn; const RMascii *p; hdr_t h; if (request == NULL) return(-1); url = request->url; purl = request->purl; conn = request->conn; /* get headers */ do { switch ((h = _http_next_header(conn, &p))) { case hdr_syserror: _fetch_syserr(); return (-1); case hdr_error: _http_seterr(HTTP_PROTOCOL_ERROR); return (-1); case hdr_content_length: _http_parse_length(p, &request->clength); break; case hdr_content_range: _http_parse_range(p, &request->offset, &request->length, &request->size); break; case hdr_last_modified: _http_parse_mtime(p, &request->mtime); break; case hdr_location: if (!HTTP_REDIRECT(conn->err)) break; if (request->new) RMFree(request->new); if (request->verbose) _fetch_info("%d redirect to %s", conn->err, p); if (*p == '/') /* absolute path */ request->new = fetchMakeURL(url->scheme, url->host, url->port, p, url->user, url->pwd); else request->new = fetchParseURL(p); if (request->new == NULL) { /* XXX should set an error code */ RMDBGLOG((ENABLE, "failed to parse new URL\n")); return(-1); } if (!*request->new->user && !*request->new->pwd) { strcpy(request->new->user, url->user); strcpy(request->new->pwd, url->pwd); } request->new->offset = url->offset; request->new->length = url->length; break; case hdr_transfer_encoding: /* XXX weak test*/ request->chunked = (strcasecmp(p, "chunked") == 0); /* RMDBGLOG((HTTPDEBUG,"Chunked !!! %d\n", request->chunked)); */ break; case hdr_www_authenticate: if (conn->err != HTTP_NEED_AUTH) break; /* if we were smarter, we'd check the method and realm */ break; case hdr_connection: /* Assume the connection will close, need to reopen in * case of open connection */ if (request->open) request->need_reopen = 1; case hdr_end: /* fall through */ case hdr_unknown: /* ignore */ break; } } while (h > hdr_end); return(0);} /** * Send a single HTTP request * @param request - the HTTP request * @return -1 on error, 0 if redirect, 1 if HIT. In case of a redirect, the * "new" field is set to the redirected URL. */ static RMint32 _http_single_request(struct http_request_s *request){ RMint32 status; if (request == NULL) return(-1); request->new = NULL; request->chunked = 0; request->offset = 0; request->clength = -1; request->length = -1; request->mtime = 0; status = __http_connect(request); if (status < 0) return(-1); status = __http_send_request(request); if (status < 0) return(status);get_reply: status = __http_get_reply(request); if (status < 0) return(status); status = __http_get_headers(request); if (status < 0) return(status); if( request->conn->err == HTTP_CONTINUE) { goto get_reply; } /* we need to provide authentication */ if (request->conn->err == HTTP_NEED_AUTH) { request->e = request->conn->err; request->need_auth = 1; _fetch_close(request->conn); request->conn = NULL; return(0); } /* requested range not satisfiable */ if (request->conn->err == HTTP_BAD_RANGE) { if (request->url->offset == request->size && request->url->length == 0) { /* asked for 0 bytes; fake it */ request->offset = request->url->offset; request->conn->err = HTTP_OK; return(1); } else { _http_seterr(request->conn->err); return(-1); } } /* we have a hit or an error */ if (request->conn->err == HTTP_OK || request->conn->err == HTTP_PARTIAL || HTTP_ERROR(request->conn->err)) return(1); /* all other cases: we got a redirect */ request->e = request->conn->err; request->need_auth = 0; _fetch_close(request->conn); request->conn = NULL; if (!request->new) { RMDBGLOG((ENABLE, "redirect with no new location\n")); return(1); } return(0);}/* * Send a request and process the reply * * @param URL - url to fetch * @param op - operation requested (GET, POST, ...) * @param us - url stat * @param purl - proxy url * @param flasg * @return HTTPFile * * */static HTTPFile *_http_request(struct url *URL, const RMascii *op, struct url_stat *us, struct url *purl, RMHTTPFlags flags){ struct http_request_s *request; RMint32 i, n, status; HTTPFile *f; request = (struct http_request_s *) RMMalloc(sizeof(struct http_request_s)); if (request == NULL){ RMDBGLOG((ENABLE,"Cannot malloc\n")); return NULL; } RMMemset(request, 0, sizeof(struct http_request_s)); /* Handle the flags */ request->direct = (flags & RM_HTTP_NO_PROXY); request->noredirect = (flags & RM_HTTP_NO_REDIRECT); request->verbose = (flags & RM_HTTP_VERBOSE); request->open = (flags & RM_HTTP_OPEN_CACHED); if (request->open){ request->cache = init_cache(CACHENBUFFER, CACHEBUFFERSIZE); if (request->cache == NULL) goto ouch; } if ((flags & RM_HTTP_CUSTOM_HEADER) && (fetchCustomHeader != NULL)){ request->custom_header = RMMallocAndDuplicateAscii(fetchCustomHeader); } if ((flags & RM_HTTP_CUSTOM_HOOKS) && (fetchCustomCookie != NULL) && (fetchCustomHooks != NULL)){ request->custom_cookie = fetchCustomCookie; request->custom_hooks = fetchCustomHooks; fetchCustomCookie = NULL; fetchCustomHooks = NULL; /* Perform a custom open hook if present */ if (request->custom_hooks->open != NULL) request->custom_hooks->open(request->custom_cookie); } /* try the provided URL first */ request->url = URL; /* First request, open mode, only HEAD */ if (request->open) request->op = "HEAD"; else request->op = op; request->us = us; request->purl = purl; request->flags = flags; request->e = HTTP_PROTOCOL_ERROR; request->need_auth = 0; request->size = -1; if (request->direct && request->purl) { fetchFreeURL(request->purl); request->purl = NULL; } /* if the A flag is set, we only get one try */ n = request->noredirect ? 1 : MAX_REDIRECT; i = 0; do { status = _http_single_request(request); if (status < 0) goto ouch; else if (status > 0) break; if (request->url != URL) fetchFreeURL(request->url); request->url = request->new; request->new = NULL; } while (++i < n); /* we failed, or ran out of retries */ if (request->conn == NULL) { _http_seterr(request->e); goto ouch; } if (request->open) request->op = op; RMDBGLOG((HTTPDEBUG, "offset %lld, length %lld," " size %lld, clength %lld\n", (RMint64)request->offset, (RMint64)request->length, (RMint64)request->size, (RMint64)request->clength)); /* check for inconsistencies, computed length and clength should be the same if set */ if (request->clength != -1 && request->length != -1 && request->clength != request->length) { _http_seterr(HTTP_PROTOCOL_ERROR); goto ouch; } /* Content-Length: not provided, use computed length if we had a Range: */ if (request->clength == -1 && request->length != -1) request->clength = request->length; /* We allow request->length != request->size, length is length of this * request, whereas size is the total length of the target */ /* if (request->length != -1 && request->size != -1 && request->length != request->size) { _http_seterr(HTTP_PROTOCOL_ERROR); goto ouch; }*/ /* For a closed connection, use the content length as the size */ if (request->size == -1 && !request->open) request->size = request->clength; /* fill in stats */ if (request->us) { request->us->size = request->size; request->us->atime = request->us->mtime = request->mtime; } /* too far? */ if (URL->offset > 0 && request->offset > URL->offset) { _http_seterr(HTTP_PROTOCOL_ERROR); goto ouch; } /* report back real offset and size */ URL->offset = request->offset; URL->length = request->clength; /* wrap it up in a HTTPFile*/ if ((f = _http_funopen(request)) == NULL) { _fetch_syserr(); goto ouch; } /*if (request->url != URL) fetchFreeURL(request->url); if (request->purl) fetchFreeURL(request->purl);*/ if (HTTP_ERROR(request->conn->err)) { fetchClose(f); f = NULL; } return (f);ouch: if (request->cache) destroy_cache(request->cache); if (request->url) fetchFreeURL(request->url); if (request->purl) fetchFreeURL(request->purl); if (request->conn != NULL) _fetch_close(request->conn); if (request->host != NULL) RMFree(request->host); if (request->custom_header != NULL) RMFree(request->custom_header); RMFree(request); return (NULL);}/***************************************************************************** * Entry points *//** * Set custom hooks. The custom hooks will be used if the * RM_HTTP_CUSTOM_HOOKS flag is set during the fetchOpen. * * @param cookie - cookie used by the hooks. * @param hooks - set of custom callbacks that use the cookie. * @return void */void fetchSetCustomHooks(void *cookie, HttpHookOps *hooks){ fetchCustomCookie = cookie; fetchCustomHooks = hooks;}/** * Set custom headers. The custom headers will be used if the * RM_HTTP_CUSTOM_HEADER flag is set during the fetchOpen. * * @param header - custom header, should use "\r\n" as end of line, NULL * terminated. The final "\r\n" will be added upon sending over * the wire. This string will be duplicated by each fetchOpen, * so it should ne be freed before the fetchOpen. * @return void */void fetchSetCustomHeader(RMascii *header){ fetchCustomHeader = header;}/* * Retrieve and stat a file by HTTP */HTTPFile *fetchXGetHTTP(struct url *URL, struct url_stat *us, RMHTTPFlags flags){ return (_http_request(URL, "GET", us, _http_get_proxy(flags), flags));}/* * Retrieve a file by HTTP */HTTPFile *fetchGetHTTP(struct url *URL, RMHTTPFlags flags){ return (fetchXGetHTTP(URL, NULL, flags));}HTTPFile *fetchOpen(const RMascii *URL, RMHTTPFlags flags){ struct url *url; RMDBGLOG((ENABLE,"Open %s\n", URL)); url = fetchParseURL(URL); if (url == NULL) return(NULL); return(fetchXGetHTTP(url, NULL, flags));}/* * Get an HTTP document's metadata */RMint32fetchStatHTTP(struct url *URL, struct url_stat *us, RMHTTPFlags flags){ HTTPFile *f; f = _http_request(URL, "HEAD", us, _http_get_proxy(flags), flags); if (f == NULL) return (-1); fetchClose(f); return (0);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -