⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http.c

📁 wget讓你可以在console介面下
💻 C
📖 第 1 页 / 共 5 页
字号:
/* HTTP support.   Copyright (C) 2005 Free Software Foundation, Inc.This file is part of GNU Wget.GNU Wget is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or (at your option) any later version.GNU Wget is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with Wget; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.In addition, as a special exception, the Free Software Foundationgives permission to link the code of its release of Wget with theOpenSSL project's "OpenSSL" library (or with modified versions of itthat use the same license as the "OpenSSL" library), and distributethe linked executables.  You must obey the GNU General Public Licensein all respects for all of the code used other than "OpenSSL".  If youmodify this file, you may extend this exception to your version of thefile, but you are not obligated to do so.  If you do not wish to doso, delete this exception statement from your version.  */#include <config.h>#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#ifdef HAVE_STRING_H# include <string.h>#else# include <strings.h>#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <assert.h>#include <errno.h>#if TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# if HAVE_SYS_TIME_H#  include <sys/time.h># else#  include <time.h># endif#endif#ifndef errnoextern int errno;#endif#include "wget.h"#include "utils.h"#include "url.h"#include "host.h"#include "retr.h"#include "connect.h"#include "netrc.h"#ifdef HAVE_SSL# include "ssl.h"#endif#ifdef ENABLE_NTLM# include "http-ntlm.h"#endif#include "cookies.h"#ifdef ENABLE_DIGEST# include "gen-md5.h"#endif#include "convert.h"extern char *version_string;extern SUM_SIZE_INT total_downloaded_bytes;extern FILE *output_stream;extern int output_stream_regular;#ifndef MIN# define MIN(x, y) ((x) > (y) ? (y) : (x))#endifstatic int cookies_loaded_p;static struct cookie_jar *wget_cookie_jar;#define TEXTHTML_S "text/html"#define TEXTXHTML_S "application/xhtml+xml"/* Some status code validation macros: */#define H_20X(x)        (((x) >= 200) && ((x) < 300))#define H_PARTIAL(x)    ((x) == HTTP_STATUS_PARTIAL_CONTENTS)#define H_REDIRECTED(x) ((x) == HTTP_STATUS_MOVED_PERMANENTLY		\                         || (x) == HTTP_STATUS_MOVED_TEMPORARILY	\			 || (x) == HTTP_STATUS_SEE_OTHER		\			 || (x) == HTTP_STATUS_TEMPORARY_REDIRECT)/* HTTP/1.0 status codes from RFC1945, provided for reference.  *//* Successful 2xx.  */#define HTTP_STATUS_OK			200#define HTTP_STATUS_CREATED		201#define HTTP_STATUS_ACCEPTED		202#define HTTP_STATUS_NO_CONTENT		204#define HTTP_STATUS_PARTIAL_CONTENTS	206/* Redirection 3xx.  */#define HTTP_STATUS_MULTIPLE_CHOICES	300#define HTTP_STATUS_MOVED_PERMANENTLY	301#define HTTP_STATUS_MOVED_TEMPORARILY	302#define HTTP_STATUS_SEE_OTHER           303 /* from HTTP/1.1 */#define HTTP_STATUS_NOT_MODIFIED	304#define HTTP_STATUS_TEMPORARY_REDIRECT  307 /* from HTTP/1.1 *//* Client error 4xx.  */#define HTTP_STATUS_BAD_REQUEST		400#define HTTP_STATUS_UNAUTHORIZED	401#define HTTP_STATUS_FORBIDDEN		403#define HTTP_STATUS_NOT_FOUND		404#define HTTP_STATUS_RANGE_NOT_SATISFIABLE 416/* Server errors 5xx.  */#define HTTP_STATUS_INTERNAL		500#define HTTP_STATUS_NOT_IMPLEMENTED	501#define HTTP_STATUS_BAD_GATEWAY		502#define HTTP_STATUS_UNAVAILABLE		503enum rp {  rel_none, rel_name, rel_value, rel_both};struct request {  const char *method;  char *arg;  struct request_header {    char *name, *value;    enum rp release_policy;  } *headers;  int hcount, hcapacity;};/* Create a new, empty request.  At least request_set_method must be   called before the request can be used.  */static struct request *request_new (void){  struct request *req = xnew0 (struct request);  req->hcapacity = 8;  req->headers = xnew_array (struct request_header, req->hcapacity);  return req;}/* Set the request's method and its arguments.  METH should be a   literal string (or it should outlive the request) because it will   not be freed.  ARG will be freed by request_free.  */static voidrequest_set_method (struct request *req, const char *meth, char *arg){  req->method = meth;  req->arg = arg;}/* Return the method string passed with the last call to   request_set_method.  */static const char *request_method (const struct request *req){  return req->method;}/* Free one header according to the release policy specified with   request_set_header.  */static voidrelease_header (struct request_header *hdr){  switch (hdr->release_policy)    {    case rel_none:      break;    case rel_name:      xfree (hdr->name);      break;    case rel_value:      xfree (hdr->value);      break;    case rel_both:      xfree (hdr->name);      xfree (hdr->value);      break;    }}/* Set the request named NAME to VALUE.  Specifically, this means that   a "NAME: VALUE\r\n" header line will be used in the request.  If a   header with the same name previously existed in the request, its   value will be replaced by this one.  A NULL value means do nothing.   RELEASE_POLICY determines whether NAME and VALUE should be released   (freed) with request_free.  Allowed values are:    - rel_none     - don't free NAME or VALUE    - rel_name     - free NAME when done    - rel_value    - free VALUE when done    - rel_both     - free both NAME and VALUE when done   Setting release policy is useful when arguments come from different   sources.  For example:     // Don't free literal strings!     request_set_header (req, "Pragma", "no-cache", rel_none);     // Don't free a global variable, we'll need it later.     request_set_header (req, "Referer", opt.referer, rel_none);     // Value freshly allocated, free it when done.     request_set_header (req, "Range",                         aprintf ("bytes=%s-", number_to_static_string (hs->restval)),			 rel_value);   */static voidrequest_set_header (struct request *req, char *name, char *value,		    enum rp release_policy){  struct request_header *hdr;  int i;  if (!value)    {      /* A NULL value is a no-op; if freeing the name is requested,	 free it now to avoid leaks.  */      if (release_policy == rel_name || release_policy == rel_both)	xfree (name);      return;    }  for (i = 0; i < req->hcount; i++)    {      hdr = &req->headers[i];      if (0 == strcasecmp (name, hdr->name))	{	  /* Replace existing header. */	  release_header (hdr);	  hdr->name = name;	  hdr->value = value;	  hdr->release_policy = release_policy;	  return;	}    }  /* Install new header. */  if (req->hcount >= req->hcapacity)    {      req->hcapacity <<= 1;      req->headers = xrealloc (req->headers, req->hcapacity * sizeof (*hdr));    }  hdr = &req->headers[req->hcount++];  hdr->name = name;  hdr->value = value;  hdr->release_policy = release_policy;}/* Like request_set_header, but sets the whole header line, as   provided by the user using the `--header' option.  For example,   request_set_user_header (req, "Foo: bar") works just like   request_set_header (req, "Foo", "bar").  */static voidrequest_set_user_header (struct request *req, const char *header){  char *name;  const char *p = strchr (header, ':');  if (!p)    return;  BOUNDED_TO_ALLOCA (header, p, name);  ++p;  while (ISSPACE (*p))    ++p;  request_set_header (req, xstrdup (name), (char *) p, rel_name);}/* Remove the header with specified name from REQ.  Returns 1 if the   header was actually removed, 0 otherwise.  */static intrequest_remove_header (struct request *req, char *name){  int i;  for (i = 0; i < req->hcount; i++)    {      struct request_header *hdr = &req->headers[i];      if (0 == strcasecmp (name, hdr->name))	{	  release_header (hdr);	  /* Move the remaining headers by one. */	  if (i < req->hcount - 1)	    memmove (hdr, hdr + 1, (req->hcount - i - 1) * sizeof (*hdr));	  --req->hcount;	  return 1;	}    }  return 0;}#define APPEND(p, str) do {			\  int A_len = strlen (str);			\  memcpy (p, str, A_len);			\  p += A_len;					\} while (0)/* Construct the request and write it to FD using fd_write.  */static intrequest_send (const struct request *req, int fd){  char *request_string, *p;  int i, size, write_error;  /* Count the request size. */  size = 0;  /* METHOD " " ARG " " "HTTP/1.0" "\r\n" */  size += strlen (req->method) + 1 + strlen (req->arg) + 1 + 8 + 2;  for (i = 0; i < req->hcount; i++)    {      struct request_header *hdr = &req->headers[i];      /* NAME ": " VALUE "\r\n" */      size += strlen (hdr->name) + 2 + strlen (hdr->value) + 2;    }  /* "\r\n\0" */  size += 3;  p = request_string = alloca_array (char, size);  /* Generate the request. */  APPEND (p, req->method); *p++ = ' ';  APPEND (p, req->arg);    *p++ = ' ';  memcpy (p, "HTTP/1.0\r\n", 10); p += 10;  for (i = 0; i < req->hcount; i++)    {      struct request_header *hdr = &req->headers[i];      APPEND (p, hdr->name);      *p++ = ':', *p++ = ' ';      APPEND (p, hdr->value);      *p++ = '\r', *p++ = '\n';    }  *p++ = '\r', *p++ = '\n', *p++ = '\0';  assert (p - request_string == size);#undef APPEND  DEBUGP (("\n---request begin---\n%s---request end---\n", request_string));  /* Send the request to the server. */  write_error = fd_write (fd, request_string, size - 1, -1.0);  if (write_error < 0)    logprintf (LOG_VERBOSE, _("Failed writing HTTP request: %s.\n"),	       strerror (errno));  return write_error;}/* Release the resources used by REQ. */static voidrequest_free (struct request *req){  int i;  xfree_null (req->arg);  for (i = 0; i < req->hcount; i++)    release_header (&req->headers[i]);  xfree_null (req->headers);  xfree (req);}/* Send the contents of FILE_NAME to SOCK.  Make sure that exactly   PROMISED_SIZE bytes are sent over the wire -- if the file is   longer, read only that much; if the file is shorter, report an error.  */static intpost_file (int sock, const char *file_name, wgint promised_size){  static char chunk[8192];  wgint written = 0;  int write_error;  FILE *fp;  DEBUGP (("[writing POST file %s ... ", file_name));  fp = fopen (file_name, "rb");  if (!fp)    return -1;  while (!feof (fp) && written < promised_size)    {      int towrite;      int length = fread (chunk, 1, sizeof (chunk), fp);      if (length == 0)	break;      towrite = MIN (promised_size - written, length);      write_error = fd_write (sock, chunk, towrite, -1.0);      if (write_error < 0)	{	  fclose (fp);	  return -1;	}      written += towrite;    }  fclose (fp);  /* If we've written less than was promised, report a (probably     nonsensical) error rather than break the promise.  */  if (written < promised_size)    {      errno = EINVAL;      return -1;    }  assert (written == promised_size);  DEBUGP (("done]\n"));  return 0;}static const char *response_head_terminator (const char *hunk, int oldlen, int peeklen){  const char *start, *end;  /* If at first peek, verify whether HUNK starts with "HTTP".  If     not, this is a HTTP/0.9 request and we must bail out without     reading anything.  */  if (oldlen == 0 && 0 != memcmp (hunk, "HTTP", MIN (peeklen, 4)))    return hunk;  if (oldlen < 4)    start = hunk;  else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -