All pastes #162383 Raw Edit

VIX

public c v1 · immutable
·published 2006-09-06 14:04 UTC
rendered paste body
/** * HTTP/HTTPS protocol support  * * Copyright (C) 2000-2005 by * Jeffrey Fulmer - <jeff@joedog.org> * This file is distributed as part of Siege  * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <setup.h>#include <http.h>#include <stdio.h>#include <stdarg.h>#include <cookie.h>#include <string.h>#include <joedog/defs.h>#define MAXFILE 10240#define REQBUF  40960 private char *__parse_pair(char **str);/** * HTTPS tunnel; set up a secure tunnel with the * proxy server. CONNECT server:port HTTP/1.0 */BOOLEANhttps_tunnel_request(CONN *C, char *host, int port){  size_t  rlen, n;  char    request[256];  if(C->prot == HTTPS && my.proxy.required){    snprintf(      request, sizeof(request),      "CONNECT %s:%d HTTP/1.0\015\012"      "User-agent: Proxy-User\015\012"      "\015\012",      host, port    );        rlen = strlen(request);     if(my.debug || my.get){fprintf(stdout, "%s", request); fflush(stdout);}    if((n = socket_write(C, request, rlen)) != rlen){      joe_error( "socket_write: ERROR" );      return FALSE;    }  } else {    return FALSE;   }  return TRUE;}inthttps_tunnel_response(CONN *C){  int  x, n;  char c;  char line[256];  int  code = 100;  while(TRUE){    x = 0;    memset( &line, 0, sizeof( line ));    while((n = read(C->sock, &c, 1)) == 1){      line[x] = c;      if(my.debug || my.get){ printf("%c", c ); fflush(stdout); }      if((line[0] == '\n') || (line[1] == '\n')){        return code;      }      if( line[x] == '\n' ) break;      x ++;    }    line[x]=0;    if( strncasecmp( line, "http", 4 ) == 0 ){      code = atoi(line + 9);    }  }}/** * returns int, ( < 0 == error ) * formats and sends an HTTP/1.0 request */inthttp_get(CONN *C, char *host, int port, char *path){  int  rlen;  char *protocol;   char *keepalive;  char authwww[128];  char authpxy[128];  char request[REQBUF];    char portstr[16];  char fullpath[4096];  char cookie[MAX_COOKIE_SIZE+10];  memset(cookie,  0, sizeof cookie);  memset(request, 0, sizeof request);  memset(portstr, 0, sizeof portstr);  /* Request path based on proxy settings */  if(my.proxy.required){    sprintf(      fullpath, "%s://%s:%d%s", C->prot == HTTP?"http":"https", host, port, path     );  }   else{    sprintf(fullpath, "%s", path);  }  if((port==80 && C->prot==HTTP) || (port==443 && C->prot==HTTPS)){    portstr[0] = '\0';    } else {    snprintf(portstr, sizeof portstr, ":%d", port);  }  /* HTTP protocol string */  protocol  = (my.protocol == TRUE)?"HTTP/1.1":"HTTP/1.0";  keepalive = (C->connection.keepalive == TRUE)?"keep-alive":"close";  get_cookie_header(pthread_self(), host, cookie);   if( C->auth.www ){    rlen = snprintf(      authwww, sizeof(authwww),       "Authorization: %s %s\015\012",       (C->auth.type.www==BASIC)?"Basic":"Digest", my.auth.encode    );  }  if( C->auth.proxy ){    rlen = snprintf(      authpxy, sizeof(authpxy),       "Proxy-Authorization: %s %s\015\012",       (C->auth.type.www==BASIC)?"Basic":"Digest", my.proxy.encode    );  }  /**    * build a request string to pass to the server          */  rlen = snprintf(    request, sizeof( request ),    "GET %s %s\015\012"    "Host: %s%s\015\012"     "%s"    "%s"    "%s"    "Accept: */*\015\012"    "Accept-Encoding: * \015\012"    "User-Agent: %s\015\012%s"    "Connection: %s\015\012\015\012",      fullpath, protocol, host, portstr,    (C->auth.www==TRUE)?authwww:"",    (C->auth.proxy==TRUE)?authpxy:"",    (strlen(cookie) > 8)?cookie:"",     my.uagent, my.extra, keepalive   );    if(my.debug || my.get){ printf("%s\n", request); fflush(stdout); }  if(rlen < 0 || rlen > (int)sizeof(request))     joe_fatal("http_get: request buffer overrun!");  if((socket_write(C, request, rlen)) < 0){    return -1;  }    return 0;}/** * returns int, ( < 0 == error ) * formats and sends an HTTP/1.0 request */inthttp_post( CONN *C, char *host, int port, char *path, char *data, size_t len ){  int  rlen;  char authwww[128];  char authpxy[128];   char request[REQBUF];   char portstr[16];  char *protocol;   char *keepalive;  char cookie[MAX_COOKIE_SIZE];  char fullpath[4096];  memset(cookie,  0, sizeof(cookie));  memset(request, 0, sizeof(request));  memset(portstr, 0, sizeof portstr);  if( my.proxy.required ){   sprintf(      fullpath,       "%s://%s:%d%s",       C->prot == 0?"http":"https", host, port, path     );   }  else{    sprintf(fullpath, "%s", path);  }  if((port==80 && C->prot==HTTP) || (port==443 && C->prot==HTTPS)){    portstr[0] = '\0';  ;  } else {    snprintf(portstr, sizeof portstr, ":%d", port);  }  /* HTTP protocol string */  protocol  = (my.protocol == TRUE)?"HTTP/1.1":"HTTP/1.0";  keepalive = (C->connection.keepalive == TRUE)?"keep-alive":"close";  get_cookie_header(pthread_self(), host, cookie);  if( C->auth.www ){    rlen = snprintf(      authwww, sizeof(authwww),      "Authorization: %s %s\015\012",      (C->auth.type.www==BASIC)?"Basic":"Digest", my.auth.encode    );  }  if( C->auth.proxy ){    rlen = snprintf(      authpxy, sizeof(authpxy),      "Proxy-Authorization: %s %s\015\012",      (C->auth.type.www==BASIC)?"Basic":"Digest", my.proxy.encode    );  }       /* build a request string to     pass to the server       */  rlen = snprintf(    request, sizeof(request),    "POST %s %s\015\012"    "Host: %s%s\015\012"    "%s"    "%s"    "%s"    "Accept: */*\015\012"    "Accept-Encoding: * \015\012"    "User-Agent: %s\015\012%s"    "Connection: %s\015\012"    "Content-type: application/x-www-form-urlencoded\015\012"    "Content-length: %ld\015\012\015\012",    fullpath, protocol, host, portstr,    (C->auth.www==TRUE)?authwww:"",    (C->auth.proxy==TRUE)?authpxy:"",    (strlen(cookie) > 8)?cookie:"",     my.uagent, my.extra, keepalive, (long)len  );   if( rlen + len < sizeof(request)){    memcpy(request + rlen, data, len);    request[rlen+len] = 0;  }  rlen += len;    if(my.debug || my.get){ printf("%s\n", request); fflush(stdout); }  if(rlen<0 || rlen>(int)sizeof(request) )    joe_fatal("http_post: request buffer overrun!");   if((socket_write(C, request, rlen)) < 0){    return -1;  }  return 0;}/** * returns HEADERS struct * reads from http/https socket and parses * header information into the struct. */HEADERS *http_read_headers(CONN *C, char *host){   int  x;             /* while loop index      */  int  n;             /* assign socket_read    */  char c;             /* assign char read      */  int  len   = 0;     /* size length of line   */  char *line = NULL;  /* assign chars read     */  HEADERS *h;         /* struct to hold it all */    h = xcalloc(sizeof(HEADERS), 1);    while(TRUE){    x = 0;    memset(&line, 0, sizeof(line));    while((n = socket_read(C, &c, 1)) == 1){      if(x >= len){        len += 2048;        line = (char*)xrealloc(line, len);      }      line[x] = c;       if(my.debug || my.get){ printf("%c", c ); fflush(stdout); }      if((line[0] == '\n') || (line[1] == '\n')){         xfree(line);        return h;      }      if(line[x] == '\n') break;      x ++;    }    line[x]=0;    /* strip trailing CR */    if (x > 0 && line[x-1] == '\r') line[x-1]=0;    if( strncasecmp( line, "http", 4 ) == 0 ){      strncpy( h->head, line, 8 );      h->code = atoi( line + 9 );     }    if( strncasecmp( line, "content-length: ", 16 ) == 0 ){       C->content.length = atoi( line + 16 );     }    if(strncasecmp( line, "set-cookie: ", 12 ) == 0){      if(my.cookies){        char* cookie = line + 12;        int cookie_len = strlen(cookie);        if(cookie_len + 1 > (int)sizeof(h->cookie)){          cookie_len = (int)sizeof(h->cookie) - 1;        }        memset(h->cookie, 0, sizeof(h->cookie));        strncpy(h->cookie, line+12, cookie_len);        add_cookie(pthread_self(), host, h->cookie);      }    }    if(strncasecmp(line, "connection: ", 12) == 0){      if(strncasecmp(line+12, "keep-alive", 10) == 0){        h->keepalive = 1;      }      else if(strncasecmp(line+12, "close", 5) == 0){        h->keepalive = 0;      }    }    if(strncasecmp(line, "keep-alive: ", 12) == 0){      char *tmp    = "";      char *option = "", *value = "";      char *newline = (char*)line;      while((tmp = __parse_pair(&newline)) != NULL){        option = tmp;        while(*tmp && !ISSPACE((int)*tmp) && !ISSEPARATOR(*tmp))          tmp++;        *tmp++=0;        while(ISSPACE((int)*tmp) || ISSEPARATOR(*tmp))          tmp++;        value  = tmp;        while(*tmp)          tmp++;          if(!strncasecmp( option, "timeout", 7)){          C->connection.timeout = atoi(value);        }        if(!strncasecmp(option, "max", 3)){          C->connection.max     = atoi(value);        }      }    }    if(strncasecmp(line, "location: ", 10) == 0){      size_t len  = strlen(line);      h->redirect = xmalloc(len);      memcpy(h->redirect, line+10, len-10);      h->redirect[len-10] = 0;    }    if(strncasecmp(line, "www-authenticate: ", 18) == 0){      char *tmp;      int   tmp_len;      h->auth.www = TRUE;      if(strncasecmp(line+19, "digest", 6) == 0){        h->auth.type.www = DIGEST;      } else {        h->auth.type.www = BASIC;      }      tmp = strchr( line, ':' );      if (tmp == NULL) {        printf("I shat myself so hard..\n");        return NULL;      }      if(h->auth.www && tmp) {        tmp++;        tmp_len = strlen(tmp);        if(tmp[0] == '"' && tmp[tmp_len - 1] == '"'){           tmp++;           tmp_len -= 2;           tmp[tmp_len] = '\0';         }        if(tmp_len + 1 > (int)sizeof(h->auth.realm.www)){           tmp_len = (int)sizeof(h->auth.realm.www) - 1;        }        strncpy( h->auth.realm.www, tmp, tmp_len );      }    }    if(strncasecmp(line, "proxy-authenticate: ", 20) == 0){      char *tmp;      int   tmp_len;      h->auth.proxy = TRUE;      if(strncasecmp(line+21, "digest", 6) == 0){        h->auth.type.proxy = DIGEST;      } else {        h->auth.type.proxy = BASIC;      }         tmp = strchr(line, '=');      if(h->auth.proxy && tmp) {        tmp++;        tmp_len = strlen(tmp);        if(tmp[0] == '"' && tmp[tmp_len - 1] == '"'){           tmp++;           tmp_len -= 2;           tmp[tmp_len] = '\0';         }        if(tmp_len + 1 > (int)sizeof(h->auth.realm.proxy)){          tmp_len = (int)sizeof(h->auth.realm.proxy) - 1;        }        strncpy(h->auth.realm.proxy, tmp, tmp_len);      }    }                          if(strncasecmp(line, "transfer-encoding: ", 19) == 0){      if(strncasecmp(line+20, "chunked", 7)){        C->content.transfer = CHUNKED;       } else if(strncasecmp( line+20, "trailer", 7)){        C->content.transfer = TRAILER;       } else {        C->content.transfer = NONE;      }    }    if(n == 0){      xfree(line);      return h;    }    if(n <  0){      xfree(line);      xfree(h);      return(NULL);     }   } /* end of while TRUE */  xfree(line);  return h;}inthttp_chunk_size(CONN *C){  int    n;  char   *end;  size_t length;  memset(C->chkbuf, 0, sizeof(C->chkbuf));  if((n = socket_readline(C, C->chkbuf, sizeof(C->chkbuf))) < 1){    joe_error("http.c: unable to determine chunk size");    return -1;  }  if(((C->chkbuf[0] == '\n')||(strlen(C->chkbuf)==0)||(C->chkbuf[0] == '\r'))){    return -1;  }   errno  = 0;  if(!isxdigit((unsigned)*C->chkbuf))    return -1;  length = strtoul(C->chkbuf, &end, 16);  if((errno == ERANGE) || (end == C->chkbuf)){    joe_error("http.c: bad chunk line %s\n", C->chkbuf);    return 0;  } else {    return length;  }  return -1;}  /** * returns ssize_t */ssize_thttp_read(CONN *C){   int    n      = 0;  int    chunk  = 0;  size_t bytes  = 0;  size_t length = 0;  static char body[MAXFILE];  if( C == NULL )    joe_fatal("C is NULL!\n");   if(C->content.length > 0){    length = (C->content.length < MAXFILE)?C->content.length:MAXFILE;    do {      memset(body, 0, sizeof(body));      if(( n = socket_read(C, body, length)) == 0 )        break;      bytes += n;      length = (C->content.length - bytes < MAXFILE)?C->content.length-bytes:MAXFILE;    } while(bytes < C->content.length);   } else if(my.chunked && C->content.transfer == CHUNKED) {    int tries = 0;    while(tries < 256) {      chunk = http_chunk_size(C);      if(chunk == 0)        break;      else if(chunk < 0) {        tries ++;        continue;      }      do {        int n;        memset(body, 0, MAXFILE);        n = socket_read(C, body, (chunk>MAXFILE)?MAXFILE:chunk);        chunk -= n;        bytes += n;      } while(chunk > 0);    }  } else {    do {      memset(body, 0, sizeof(body));      if((n = socket_read(C, body, sizeof(body))) == 0)        break;      bytes += n;    } while(TRUE);  }  return(bytes);}/** * parses option=value pairs from an * http header, see keep-alive: above * while(( tmp = __parse_pair( &newline )) != NULL ){ *   do_something( tmp ); * } */private char *__parse_pair(char **str){  int  okay  = 0;  char *p    = *str;  char *pair = NULL;   if( !str || !*str ) return NULL;  /**   * strip the header label   */  while( *p && *p != ' ' )    p++;  *p++=0;  if( !*p ){    *str   = p;    return NULL;  }   pair = p;  while( *p && *p != ';' && *p != ',' ){    if( !*p ){      *str = p;      return NULL;    }    if( *p == '=' ) okay = 1;    p++;  }  *p++ = 0;  *str = p;   if( okay )    return pair;  else    return NULL;}