欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

http.c

Google 推出一套免費的 Web 安全評估工具
C
第 1 页 / 共 3 页
字号:
    if (r->port != 443) sprintf(port_spec,":%u",r->port);  }  if (use_proxy && !r->from_ssl)    fprintf(server,      "%s http://%s:%u/%s%s%s HTTP/1.0\r\n"      "Connection: close\r\n"      "Host: %s%s\r\n"      "Accept-Encoding: identity\r\n"      "X-Ratproxy-Loop: 1\r\n"      "Content-Length: %u\r\n", r->method, r->host, r->port, r->path,      r->query ? "?" : "", r->query ? r->query : (_u8*)"",       r->host, port_spec, r->payload_len);  else    fprintf(server,      "%s /%s%s%s HTTP/1.0\r\n"      "Connection: close\r\n"      "Host: %s%s\r\n"      "Accept-Encoding: identity\r\n"      "X-Ratproxy-Loop: 1\r\n"      "Content-Length: %u\r\n", r->method, r->path,      r->query ? "?" : "", r->query ? r->query : (_u8*)"",       r->host, port_spec, r->payload_len);  if (!strip_state)    for (i=0;i<r->h.c;i++) {      /* There are several types of headers we'd rather skip         and override elsewhere. */#ifdef FORCE_NOCACHE      if (!strncasecmp(r->h.v1[i],"If-",3)) continue;#endif /* FORCE_NOCACHE */      if (!strcasecmp(r->h.v1[i],"Host")) continue;      if (!strcasecmp(r->h.v1[i],"Range")) continue;      if (!strcasecmp(r->h.v1[i],"Connection")) continue;      if (!strncasecmp(r->h.v1[i],"Proxy-",6)) continue;      if (!strcasecmp(r->h.v1[i],"Accept-Encoding")) continue;      if (!strcasecmp(r->h.v1[i],"Content-Length")) continue;      /* Override multipart boundary on requests after rewriting. */      if (!strcasecmp(r->h.v1[i],"Content-Type") && r->use_boundary) {        fprintf(server,"Content-Type: multipart/form-data; boundary=%s\r\n",r->use_boundary);        continue;      }      fprintf(server,"%s: %s\r\n",r->h.v1[i],r->h.v2[i]);    }  fprintf(server,"\r\n");  if (r->payload_len)     fwrite(r->payload,r->payload_len,1,server);  fflush(server);  /* Ok, sending complete. */  /* Process the response... */  ret = calloc(1,sizeof(struct http_response));  if (!ret) fatal("out of memory");  ret->ext = r->ext;  line = grab_line(server);  if (!line || !line[0]) http_error(client,"Malformed HTTP response",0);  x = strchr(line,' ');  if (!x || x == line) http_error(client,"HTTP response code missing",0);  *(x++) = 0;  ret->code = atoi(x);  if (ret->code < 100 || ret->code > 999)     http_error(client,"Invalid HTTP response code",0);  while (1) {    line = grab_line(server);    if (!line) http_error(client,"Premature end of server headers",0);    if (!line[0]) break;    x = strchr(line,':');    if (!x) http_error(client,"Invalid response header",0);    *x = 0;    while (isspace(*(++x)));    for (i=0;i<ret->h.c;i++)       if (!strcasecmp(line,ret->h.v1[i]) && strcmp(x,ret->h.v2[i]) &&           strncasecmp(line,"Set-Cookie",10) && strncasecmp(line,"X-Cache",7) &&           strncasecmp(line,"Server",7))        ret->has_multiple = 1;    /* Again, some headers need to be analyzed in more detail or skipped. */    /* Caching headers checks... */    if (!strcasecmp(line,"Expires")) {      exp_value = strdup(x);      if (!exp_value) fatal("out of memory");    }    if (!strcasecmp(line,"Date")) {      dat_value = strdup(x);      if (!dat_value) fatal("out of memory");    }    /* Both "no-store" and "max-age=0" are generally discouraged, but in practice,       should be sufficient, so let's be polite. */    /* TODO: These checks should be probably more robust to detect typos       such as missing whitespaces. */    if (!strcasecmp(line,"Cache-Control")) {      if (strstr(x,"no-cache") || strstr(x,"private") ||           strstr(x,"max-age=0") || strstr(x,"no-store"))        ret->cc11intent = INTENT_PRIV; else ret->cc11intent = INTENT_PUB;    }    if (!strcasecmp(line,"Pragma")) {      if (strstr(x,"no-cache")) ret->pr10intent = INTENT_PRIV;         else ret->pr10intent = INTENT_PUB;    }    if (!strcasecmp(line,"Connection")) continue;    if (!strcasecmp(line,"Content-Range")) continue;    if (!strcasecmp(line,"Content-Type")) {      _u8 *copy = strdup(x), *y;      if (!copy) fatal("out of memory");      if ((y = strrchr(copy,';'))) {        *(y++) = 0;        while (isspace(*y)) y++;        if (!strncasecmp(y,"charset=",8)) {          y += 8;          if (*y == '"' && y[strlen(y)-1] == '"') {            y[strlen(y)-1]=0;            y++;          }          ret->charset = y;        }      }       ret->mime_type  = copy;    }    if (!strcasecmp(line,"Content-Disposition")) {      _u8* y;      ret->is_attach = (strncasecmp(x,"attachment;",11) == 0) ||                        (strcasecmp(x,"attachment") == 0);      /* If filename is specified, try to grab it (it supersedes         any URL-derived ones). */      y=strrchr(x,'.');      if (y && y[1] && y[1] != '"') {        ret->ext = strdup(y + 1);        if (!ret->ext) fatal("out of memory");        y = strchr(y + 1,'"');        if (y) *y=0;      }    }    if (!strcasecmp(line,"Location")) {      ret->location = strdup(x);      if (!ret->location) fatal("out of memory");    }    if (!strcasecmp(line,"Set-Cookie")) parse_cookies(x,&ret->cookies);    if (!strcasecmp(line,"Content-Length")) {      decl_clen = atoi(x);      if (decl_clen < 0)         http_error(client,"Bogus content length returned by server.",0);      continue;    }    DYN_ADD2(ret->h,line,x);  }  /* Some final "Expires" parsing for caching headers checks... */  if (exp_value) {    _u8* year = 0, *z = strchr(exp_value,',');    ret->ex10intent = INTENT_PUB;    /* Try to extract the year, at least roughly... */    if (!isalnum(exp_value[0])) {      /* "Expires: -1" is a nasty trick, but it works. */      ret->ex10intent = INTENT_PRIV;    } else if (dat_value && (!strcmp(exp_value,dat_value) || !comp_dates(exp_value,dat_value))) {           /* Date == Expires is an alternative and valid method. */      ret->ex10intent = INTENT_PRIV;    } else {      if (z && z == exp_value + 3 && strlen(exp_value) > 11) {        /* Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123 */        year = exp_value + 11;        if (*year == ' ') year++;      } else if (z) {        /* Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 */        year = strchr(z,'-');        if (year) year = strchr(year + 1,'-');        if (year) year++;      } else if (strlen(x) > 19) {        /* Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format */        year = exp_value + 19;        if (*year == ' ') year++;      }      if (year) {        _u32 yval = atoi(year);        if (yval < 1000) {          yval += 1900;			  /* 94 -> 1994, 104 -> 2004 */          if (yval < 1970) yval += 100;   /* 03 -> 2003, 93 -> 1993 */        }        if (yval < 2008) ret->ex10intent = INTENT_PRIV;      }    }  }  /* Headers read. Grab the actual payload, regardless of content     length (but note a discrepancy, if present).  */  while (1) {    _u8 buf[1024];    _s32 i;     if ((i = fread(buf,1,1024,server)) <= 0) break;    ret->payload = realloc(ret->payload, ret->payload_len + i + 1);        if (!ret->payload) fatal("out of memory");    memcpy(ret->payload + ret->payload_len, buf, i);    ret->payload_len += i;    if (ret->payload_len > MAXPAYLOAD)      http_error(client,"Response size limit exceeded",0);  }  if (ret->payload_len)     ret->payload[ret->payload_len] = 0;  /* Let payload_len < decl_clen slip through - transmission errors happen. */  if (decl_clen >= 0 && ret->payload_len > decl_clen)    ret->has_badclen = 1;  fflush(server);  fclose(server);  return ret;}/* Just send data back to client. */void send_response(FILE* client, struct http_response* r) {  _u32 i;  setvbuf(client, cli_buf, _IOFBF, sizeof(cli_buf));  fprintf(client,    "HTTP/1.0 %u Proxied response\r\n"    "Connection: close\r\n"#ifdef FORCE_NOCACHE    "Pragma: no-cache\r\n"    "Expires: Fri, 01 Jan 1990 00:00:00 GMT\r\n"    "Cache-Control: no-cache, must-revalidate\r\n"#endif /* FORCE_NOCACHE */    "Content-Length: %u\r\n", r->code, r->payload_len);  for (i=0;i<r->h.c;i++) {#ifdef FORCE_NOCACHE    if (!strcasecmp(r->h1[i],"Expires")) continue;    if (!strcasecmp(r->h1[i],"Last-Modified")) continue;    if (!strcasecmp(r->h1[i],"Cache-Control")) continue;    if (!strcasecmp(r->h1[i],"Pragma")) continue;#endif /* FORCE_NOCACHE */    fprintf(client,"%s: %s\r\n",r->h.v1[i],r->h.v2[i]);  }  fprintf(client,"\r\n");  if (r->payload_len)    fwrite(r->payload,r->payload_len,1,client);  fflush(client);  fclose(client);}/* Calculate a checksum for response payload */void checksum_response(struct http_response* r) {  MD5_CTX ctx;  _u8  res[16];  if (use_len) {    r->cksum = r->payload_len;    return;  }  if (!r->payload_len) return;  MD5_Init(&ctx);  MD5_Update(&ctx, r->payload, r->payload_len);  MD5_Final((char*)res, &ctx);  r->cksum = *(_u64*)res;}/* Attempt charset sniffing inside the payload; currently, supports HTML http-equiv only;   kinda fuzzy, but should be good enough. *//* TODO: Make this a bit more robust; reversed http-equiv / content order is   not detected, for example. */void detect_charset(struct http_response* r) {  _u8  sniffed[33];  _u32 i, max;  _u8 got_equiv = 0;  if (r->payload_len > CHARSNIFF) max = CHARSNIFF; else max = r->payload_len;  for (i=0;i<max;i++) {    if (r->payload[i] < 0x20 && !isspace(r->payload[i])) break;    if (!strncasecmp(r->payload+i,"http-equiv",10)) got_equiv = 1;    if (r->payload[i] == '>') got_equiv = 0;    if (got_equiv && !strncasecmp(r->payload+i,"charset=",8)) {      _u32 p = 0;      _u8* cp = r->payload + i + 8;      while (p < 32 && (isalnum(*cp) || *cp == '-' || *cp == '_')) sniffed[p++] = *(cp++);      sniffed[p] = 0;      break;    }  }  if (i != max) {    if (r->charset && strcasecmp(sniffed,r->charset)) r->has_multiple = 1;    r->charset = strdup(sniffed);    if (!r->charset) fatal("out of memory");  }  if (!r->charset) return;  i = 0;  while (valid_charsets[i]) {    if (!strcasecmp(r->charset,valid_charsets[i])) return;    i++;  }  /* But note that utf8, iso_8859_2, etc, are not recognized and lead to XSS... */  r->bad_cset = 1;  if (!r->charset[0]) r->charset = 0;}#define TOHEX(c) ("0123456789abcdef"[c])/* Sanitize output; make sure it's easily reversible, too. */_u8* S(_u8* string, _u8 nl) {  _u8* ret = malloc(MAXTOKEN + 10 /* &#x00;...\0 */), *wp = ret;  if (!ret) fatal("out of memory");  while (*string) {    switch (tolower(*string)) {      /* Well, we kind-of want to maintain readaibility of text output, so let's         pay the price and let '&' through. */      case '&':      /* Quote literally */      case 'a' ... 'z':      case '0' ... '9':      case ' ':  case '+':  case '!':  case '@':  case '#':  case '$':      case '%':  case '^':  case '*':  case '(':  case ')':  case '-':      case '_':  case '=':  case '{':  case '[':  case '}':  case ']':      case ':':  case ';':  case ',':  case '.':  case '?':  case '/':      case '~':  case '`':  case '\\':        *(wp++) = *string;        break;      /* These can be harmful or confusing, so replace with HTML entities */      case '"':      case '\'':      case '<':      case '>':      case '|':      case 127 ... 255:entitify:        *(wp++) = '&';        *(wp++) = '#';        *(wp++) = 'x';        *(wp++) = TOHEX(*string / 16);        *(wp++) = TOHEX(*string % 16);        *(wp++) = ';';        break;      /* Replace with shorthand codes */      case '\r':        if (nl) {          *(wp++) = *string;        } else {          *(wp++) = '\\';          *(wp++) = 'r';        }        break;      case '\n':        if (nl) {          *(wp++) = *string;        } else {          *(wp++) = '\\';          *(wp++) = 'n';        }        break;      case '\t':        if (nl) {          *(wp++) = *string;        } else {          *(wp++) = '\\';          *(wp++) = 't';        }        break;      /* Replace with hex tokens */      default:        if (nl) goto entitify;        *(wp++) = '\\';        *(wp++) = 'x';        *(wp++) = TOHEX(*string / 16);        *(wp++) = TOHEX(*string % 16);    }    if (wp - ret >= MAXTOKEN) {      *(wp++) = '.';      *(wp++) = '.';      *(wp++) = '.';      break;    }    string++;  }  *(wp++) = 0;  return ret;}

⌨️ 快捷键说明

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