parse.c
上传用户:seven77cht
上传日期:2007-01-04
资源大小:486k
文件大小:25k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/parse.c 2.65 2000/01/19 18:58:08 amb Exp $
  3.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.5d.
  4.   Functions to parse the HTTP requests.
  5.   ******************/ /******************
  6.   Written by Andrew M. Bishop
  7.   This file Copyright 1996,97,98,99,2000 Andrew M. Bishop
  8.   It may be distributed under the GNU Public License, version 2, or
  9.   any higher version.  See section COPYING of the GNU Public license
  10.   for conditions under which this file may be redistributed.
  11.   ***************************************/
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <time.h>
  19. #include <unistd.h>
  20. #include "wwwoffle.h"
  21. #include "misc.h"
  22. #include "proto.h"
  23. #include "errors.h"
  24. #include "config.h"
  25. /*+ The time that the program went online. +*/
  26. time_t OnlineTime=0;
  27. /*+ Headers from a request that can be re-used in automatically generated requests. +*/
  28. static char *reusable_headers[]={"User-Agent",
  29.                                  "Accept",
  30.                                  "Accept-Charset",
  31.                                  "Accept-Language",
  32.                                  "From",
  33.                                  "Proxy-Authorization"};
  34. /*+ Headers that we do not allow the users to censor. +*/
  35. static char *non_censored_headers[]={"Host",
  36.                                      "Connection",
  37.                                      "Proxy-Connection",
  38.                                      "Authorization"};
  39. /*+ Headers that are difficult with HTTP/1.1. +*/
  40. static char *deleted_http11_headers[]={"If-Match",
  41.                                        "If-None-Match",
  42.                                        "If-Range",
  43.                                        "Range",
  44.                                        "Upgrade",
  45.                                        "Accept-Encoding"};
  46. /*+ The headers from the request that are re-usable. +*/
  47. static Header *reusable_header;
  48. static int AddToHeaderRaw(Header *head,char *line);
  49. /*++++++++++++++++++++++++++++++++++++++
  50.   Parse the request to the server.
  51.   char *ParseRequest Returns the URL or NULL if it failed.
  52.   int fd The file descriptor to read the request from.
  53.   Header **request_head Return the header of the request.
  54.   Body **request_body Return the body of the request.
  55.   ++++++++++++++++++++++++++++++++++++++*/
  56. char *ParseRequest(int fd,Header **request_head,Body **request_body)
  57. {
  58.  char *url=NULL,*line=NULL;
  59.  int i,length=-1;
  60.  *request_head=NULL;
  61.  *request_body=NULL;
  62.  reusable_header=CreateHeader("GET reusable HTTP/1.0rn",1);
  63.  while((line=read_line_or_timeout(fd,line,SocketTimeout)))
  64.    {
  65.     char *key,*val;
  66.     if(!*request_head) /* first line */
  67.       {
  68.        *request_head=CreateHeader(line,1);
  69.        if(!*(*request_head)->url)
  70.           return(NULL);
  71.        url=(char*)malloc(strlen((*request_head)->url)+1);
  72.        strcpy(url,(*request_head)->url);
  73.        continue;
  74.       }
  75.     if(!AddToHeaderRaw(*request_head,line))
  76.        break;
  77.     key=(*request_head)->key[(*request_head)->n-1];
  78.     val=(*request_head)->val[(*request_head)->n-1];
  79.     /* Find the content length */
  80.     if(!strcasecmp("Content-Length",key))
  81.        length=atoi(val);
  82.     /* Find re-usable headers (for recursive requests) */
  83.     for(i=0;i<sizeof(reusable_headers)/sizeof(char*);i++)
  84.        if(!strcmp(reusable_headers[i],key))
  85.           AddToHeader(reusable_header,key,val);
  86.     /* Check for firewall operation. */
  87.     if(!strcasecmp("Host",key) && url && *url=='/')
  88.       {
  89.        char *oldurl=url;
  90.        url=(char*)malloc(strlen(url)+strlen(val)+8);
  91.        strcpy(url,"http://");
  92.        strcat(url,val);
  93.        strcat(url,oldurl);
  94.        free(oldurl);
  95.       }
  96.     /* Check for passwords */
  97.     if(!strcasecmp("Authorization",key))
  98.       {
  99.        char *p=val,*copy,*userpass;
  100.        int l;
  101.        while(*p!=' ') p++;
  102.        while(*p==' ') p++;
  103.        userpass=URLEncodePassword(Base64Decode(p,&l));
  104.        p=url;
  105.        if(*url=='/')
  106.          {
  107.           char *localhost=GetLocalHost(1);
  108.           copy=(char*)malloc(strlen(url)+strlen(userpass)+strlen(localhost)+10);
  109.           strcpy(copy,"http://");
  110.           strcat(copy,userpass);
  111.           strcat(copy,"@");
  112.           strcat(copy,localhost);
  113.          }
  114.        else
  115.          {
  116.           copy=(char*)malloc(strlen(url)+strlen(userpass)+2);
  117.           while(*p!=':') p++; p++;
  118.           while(*p=='/') p++;
  119.           strncpy(copy,url,p-url);
  120.           copy[p-url]=0;
  121.           strcat(copy,userpass);
  122.           strcat(copy,"@");
  123.          }
  124.        strcat(copy,p);
  125.        free(url);
  126.        url=copy;
  127.       }
  128.    }
  129.  if(line)
  130.     free(line);
  131.  if(!*request_head)
  132.     return(NULL);
  133.  if(!strcmp("POST",(*request_head)->method) ||
  134.     !strcmp("PUT",(*request_head)->method))
  135.    {
  136.     if(length==-1)
  137.       {free(url);return(NULL);}
  138.     *request_body=CreateBody(length);
  139.     if(length)
  140.       {
  141.        int m,l=length;
  142.        do
  143.          {
  144.           m=read_data_or_timeout(fd,&(*request_body)->content[length-l],l,SocketTimeout);
  145.          }
  146.        while(m>0 && (l-=m));
  147.        if(l)
  148.          {free(url);return(NULL);}
  149.        empty_buffer(fd);
  150.       }
  151.     (*request_body)->content[length]=0;
  152.     url=(char*)realloc((void*)url,strlen(url)+40);
  153.     if(strchr(url,'?'))
  154.       {
  155.        char *from=url+strlen(url),*to=from+1;
  156.        while(*from!='?')
  157.           *to--=*from--;
  158.        *to='!';
  159.       }
  160.     else
  161.        strcat(url,"?");
  162.     sprintf(url+strlen(url),"!%s:%s.%08lx",(*request_head)->method,MakeHash((*request_body)->content),time(NULL));
  163.    }
  164.  return(url);
  165. }
  166. /*++++++++++++++++++++++++++++++++++++++
  167.   Modify the request to ask for changes since the spooled file.
  168.   int RequestChanges Returns 1 if the file needs changes made, 0 if not, or -1 in case of an error.
  169.   int fd The file descriptor of the spooled file.
  170.   Header *request_head The head of the HTTP request to modify.
  171.   ++++++++++++++++++++++++++++++++++++++*/
  172. int RequestChanges(int fd,Header *request_head)
  173. {
  174.  struct stat buf;
  175.  int status,retval=0;
  176.  Header *spooled_head=NULL;
  177.  status=ParseReply(fd,NULL,&spooled_head);
  178.  if(status==0 || fstat(fd,&buf))
  179.    {
  180.     PrintMessage(Debug,"Requesting URL (Empty or no status).");
  181.     retval=1;
  182.    }
  183.  else if(status<200 || status>=400)
  184.    {
  185.     PrintMessage(Debug,"Requesting URL (Error status).");
  186.     retval=1;
  187.    }
  188.  else
  189.    {
  190.     char *expires,*head,*val;
  191.     if(RequestExpired && (expires=GetHeader(spooled_head,"Expires",NULL)))
  192.       {
  193.        time_t since=DateToTimeT(expires);
  194.        if(since<=time(NULL))
  195.          {
  196.           PrintMessage(Debug,"Requesting URL (Expiry date of '%s').",expires);
  197.           retval=1;
  198.          }
  199.       }
  200.     if(retval==0)
  201.        if(RequestNoCache && (GetHeader(spooled_head,head="Pragma"       ,val="no-cache") ||
  202.                              GetHeader(spooled_head,head="Cache-Control",val="no-cache")))
  203.          {
  204.           PrintMessage(Debug,"Requesting URL (No cache header '%s: %s').",head,val);
  205.           retval=1;
  206.          }
  207.     if(retval==0)
  208.        if(RequestChangedOnce && buf.st_mtime>OnlineTime)
  209.          {
  210.           PrintMessage(Debug,"Not requesting URL (Only once per online session).");
  211.           retval=0;
  212.          }
  213.        else if((time(NULL)-buf.st_mtime)<RequestChanged)
  214.          {
  215.           PrintMessage(Debug,"Not requesting URL (Last changed %d seconds ago).",time(NULL)-buf.st_mtime);
  216.           retval=0;
  217.          }
  218.        else
  219.          {
  220.           AddToHeader(request_head,"If-Modified-Since",RFC822Date(buf.st_mtime,1));
  221.           PrintMessage(Debug,"Requesting URL (Making a conditional request).");
  222.           retval=1;
  223.          }
  224.    }
  225.  if(spooled_head)
  226.     FreeHeader(spooled_head);
  227.  return(retval);
  228. }
  229. /*++++++++++++++++++++++++++++++++++++++
  230.   Return the location that the URL has been moved to.
  231.   char *MovedLocation Returns the new URL.
  232.   URL *Url The original URL.
  233.   Header *reply_head The head of the original HTTP reply.
  234.   ++++++++++++++++++++++++++++++++++++++*/
  235. char *MovedLocation(URL *Url,Header *reply_head)
  236. {
  237.  char *location;
  238.  char *new;
  239.  location=GetHeader(reply_head,"Location",NULL);
  240.  if(!location)
  241.     return(NULL);
  242.  new=LinkURL(Url,location);
  243.  if(new==location)
  244.    {
  245.     new=(char*)malloc(strlen(location)+1);
  246.     strcpy(new,location);
  247.    }
  248.  return(new);
  249. }
  250. /*++++++++++++++++++++++++++++++++++++++
  251.   Create a new request for a page.
  252.   Header *RequestURL Ask for a page.
  253.   URL *Url The URL to get.
  254.   char *referer The Refering URL or NULL if none.
  255.   ++++++++++++++++++++++++++++++++++++++*/
  256. Header *RequestURL(URL *Url,char *referer)
  257. {
  258.  char *top=(char*)malloc(strlen(Url->name)+32);
  259.  Header *new;
  260.  int i;
  261.  sprintf(top,"GET %s HTTP/1.0rn",Url->name);
  262.  new=CreateHeader(top,1);
  263.  free(top);
  264.  if(Url->user)
  265.    {
  266.     char *userpass=(char*)malloc(strlen(Url->user)+(Url->pass?strlen(Url->pass):0)+2);
  267.     char *auth=(char*)malloc((strlen(Url->user)+(Url->pass?strlen(Url->pass):0))*2+16);
  268.     strcpy(userpass,Url->user);
  269.     strcat(userpass,":");
  270.     if(Url->pass)
  271.        strcat(userpass,Url->pass);
  272.     sprintf(auth,"Basic %s",Base64Encode(userpass,strlen(userpass)));
  273.     AddToHeader(new,"Authorization",auth);
  274.     free(userpass);
  275.     free(auth);
  276.    }
  277.  if(referer)
  278.     AddToHeader(new,"Referer",referer);
  279.  if(reusable_header->n)
  280.     for(i=0;i<reusable_header->n;i++)
  281.        AddToHeader(new,reusable_header->key[i],reusable_header->val[i]);
  282.  return(new);
  283. }
  284. /*++++++++++++++++++++++++++++++++++++++
  285.   Modify the request taking into account censoring of header and modified URL.
  286.   URL *Url The actual URL.
  287.   Header *request_head The head of the HTTP request possibly with a different URL.
  288.   ++++++++++++++++++++++++++++++++++++++*/
  289. void ModifyRequest(URL *Url,Header *request_head)
  290. {
  291.  int i,j;
  292.  /* Modify the top line of the header. */
  293.  free(request_head->url);
  294.  request_head->url=(char*)malloc(strlen(Url->name)+1);
  295.  strcpy(request_head->url,Url->name);
  296.  /* Remove the false arguments from POST/PUT URLs. */
  297.  if(!strcmp(request_head->method,"POST") ||
  298.     !strcmp(request_head->method,"PUT"))
  299.    {
  300.     char *pling=strstr(request_head->url,"?!");
  301.     char *pling2=strchr(++pling+1,'!');
  302.     if(pling2)
  303.        for(;pling<pling2;pling++)
  304.           *pling=*(pling+1);
  305.     *(pling-1)=0;
  306.    }
  307.  /* Add a host header */
  308.  RemoveFromHeader(request_head,"Host",NULL);
  309.  AddToHeader(request_head,"Host",Url->host);
  310.  /* Add a Connection / Proxy-Connection header */
  311.  RemoveFromHeader(request_head,"Connection",NULL);
  312.  RemoveFromHeader(request_head,"Proxy-Connection",NULL);
  313.  if(!strcmp(request_head->version,"HTTP/1.1"))
  314.     strcpy(request_head->version,"HTTP/1.0");
  315.  AddToHeader(request_head,"Connection","close");
  316.  AddToHeader(request_head,"Proxy-Connection","close");
  317.  /* Check the authorisation header. */
  318.  RemoveFromHeader(request_head,"Authorization",NULL);
  319.  if(Url->user)
  320.    {
  321.     char *userpass=(char*)malloc(strlen(Url->user)+(Url->pass?strlen(Url->pass):0)+2);
  322.     char *auth=(char*)malloc((strlen(Url->user)+(Url->pass?strlen(Url->pass):0))*2+16);
  323.     strcpy(userpass,Url->user);
  324.     strcat(userpass,":");
  325.     if(Url->pass)
  326.        strcat(userpass,Url->pass);
  327.     sprintf(auth,"Basic %s",Base64Encode(userpass,strlen(userpass)));
  328.     AddToHeader(request_head,"Authorization",auth);
  329.     free(userpass);
  330.     free(auth);
  331.    }
  332.  /* Remove some headers */
  333.  for(j=0;j<sizeof(deleted_http11_headers)/sizeof(char*);j++)
  334.     RemoveFromHeader(request_head,deleted_http11_headers[j],NULL);
  335.  RemoveFromHeader(request_head,"Pragma","wwwoffle");
  336.  /* Censor the header */
  337.  for(i=0;i<request_head->n;i++)
  338.    {
  339.     char *censor;
  340.     if(!request_head->key[i])
  341.        continue;
  342.     for(j=0;j<sizeof(non_censored_headers)/sizeof(char*);j++)
  343.        if(!strcasecmp(non_censored_headers[j],request_head->key[i]))
  344.           continue;
  345.     if((censor=CensoredHeader(Url->name,request_head->key[i],request_head->val[i])))
  346.       {
  347.        if(censor!=request_head->val[i])
  348.          {
  349.           PrintMessage(Debug,"CensorRequestHeader replaced '%s: %s' by '%s: %s'.",request_head->key[i],request_head->val[i],request_head->key[i],censor);
  350.           request_head->size+=strlen(censor)-strlen(request_head->val[i]);
  351.           free(request_head->val[i]);
  352.           request_head->val[i]=censor;
  353.          }
  354.       }
  355.     else
  356.       {
  357.        PrintMessage(Debug,"CensorRequestHeader removed '%s: %s'.",request_head->key[i],request_head->val[i]);
  358.        RemoveFromHeader(request_head,request_head->key[i],request_head->val[i]);
  359.        continue;
  360.       }
  361.     if(!strcasecmp("Referer",request_head->key[i]))
  362.       {
  363.        char *pling=strstr(request_head->val[i],"?!");
  364.        if(pling)
  365.          {
  366.           char *pling2=strchr(++pling+1,'!');
  367.           if(pling2)
  368.              for(;pling<pling2;pling++)
  369.                 *pling=*(pling+1);
  370.           *(pling-1)=0;
  371.          }
  372.       }
  373.    }
  374. }
  375. /*++++++++++++++++++++++++++++++++++++++
  376.   Change the request to one that contains an authorisation string if required.
  377.   char *proxy The name of the proxy.
  378.   Header *request_head The HTTP request head.
  379.   ++++++++++++++++++++++++++++++++++++++*/
  380. void MakeRequestAuthorised(char *proxy,Header *request_head)
  381. {
  382.  char *userpass=WhatProxyAuth(proxy);
  383.  RemoveFromHeader(request_head,"Proxy-Authorization",NULL);
  384.  if(userpass)
  385.    {
  386.     char *auth=(char*)malloc(strlen(userpass)*2+8);
  387.     sprintf(auth,"Basic %s",Base64Encode(userpass,strlen(userpass)));
  388.     AddToHeader(request_head,"Proxy-Authorization",auth);
  389.     free(userpass);
  390.     free(auth);
  391.    }
  392. }
  393. /*++++++++++++++++++++++++++++++++++++++
  394.   Change the request from one to a proxy to a normal one.
  395.   Header *request_head The head of the HTTP request.
  396.   ++++++++++++++++++++++++++++++++++++++*/
  397. void MakeRequestNonProxy(Header *request_head)
  398. {
  399.  char *p=request_head->url,*q=request_head->url;
  400.  /* The URL is already in canonical form because of the ModifyRequest() function. */
  401.  while(*p!=':')                 /* 'http://' */
  402.     p++;
  403.  p+=3;
  404.  while(*p!='/')                 /* 'www.host.domain/' */
  405.     p++;
  406.  while(*p)
  407.     *q++=*p++;
  408.  *q=0;
  409.  /* Remove the proxy connection & authorization headers. */
  410.  RemoveFromHeader(request_head,"Proxy-Connection","close");
  411.  RemoveFromHeader(request_head,"Proxy-Authorization",NULL);
  412. }
  413. /*++++++++++++++++++++++++++++++++++++++
  414.   Parse the reply from the server.
  415.   int ParseReply Return the numeric status of the reply.
  416.   int fd The file descriptor to read from (or -1 to use the Protocol's method).
  417.   URL *Url The URL that we are reading.
  418.   Header **reply_head Return the head of the HTTP reply.
  419.   ++++++++++++++++++++++++++++++++++++++*/
  420. int ParseReply(int fd,URL *Url,Header **reply_head)
  421. {
  422.  char *line=NULL;
  423.  *reply_head=NULL;
  424.  while((fd==-1 && (line=(Url->Protocol->readhead)(line))) ||
  425.        (fd!=-1 && (line=read_line(fd,line))))
  426.    {
  427.     if(!*reply_head)   /* first line */
  428.       {
  429.        *reply_head=CreateHeader(line,0);
  430.        if(!*(*reply_head)->version)
  431.           break;
  432.        continue;
  433.       }
  434.     if(!AddToHeaderRaw(*reply_head,line))
  435.        break;
  436.    }
  437.  if(!line)
  438.    return(0);
  439.  free(line);
  440.  if(*reply_head)
  441.     return((*reply_head)->status);
  442.  else
  443.     return(0);
  444. }
  445. /*++++++++++++++++++++++++++++++++++++++
  446.   Find the status of a spooled page.
  447.   int SpooledPageStatus Returns the status number.
  448.   URL *Url The URL to check.
  449.   ++++++++++++++++++++++++++++++++++++++*/
  450. int SpooledPageStatus(URL *Url)
  451. {
  452.  int spool=OpenWebpageSpoolFile(1,Url);
  453.  int status=0;
  454.  if(spool!=-1)
  455.    {
  456.     char *reply;
  457.     init_buffer(spool);
  458.     reply=read_line(spool,NULL);
  459.     if(reply)
  460.       {
  461.        sscanf(reply,"%*s %d",&status);
  462.        free(reply);
  463.       }
  464.     close(spool);
  465.    }
  466.  return(status);
  467. }
  468. /*++++++++++++++++++++++++++++++++++++++
  469.   Modify the reply taking into account censoring of the header.
  470.   Header *reply_head The head of the HTTP reply.
  471.   ++++++++++++++++++++++++++++++++++++++*/
  472. void ModifyReply(Header *reply_head)
  473. {
  474.  int i;
  475.  /* Add a Connection / Proxy-Connection header */
  476.  RemoveFromHeader(reply_head,"Connection",NULL);
  477.  RemoveFromHeader(reply_head,"Proxy-Connection",NULL);
  478.  if(!strcmp(reply_head->version,"HTTP/1.1"))
  479.     strcpy(reply_head->version,"HTTP/1.0");
  480.  AddToHeader(reply_head,"Connection","close");
  481.  AddToHeader(reply_head,"Proxy-Connection","close");
  482.  /* Censor the header */
  483.  for(i=0;i<reply_head->n;i++)
  484.    {
  485.     int j;
  486.     char *censor;
  487.     if(!reply_head->key[i])
  488.        continue;
  489.     for(j=0;j<sizeof(non_censored_headers)/sizeof(char*);j++)
  490.        if(!strcasecmp(non_censored_headers[j],reply_head->key[i]))
  491.           continue;
  492.     if((censor=CensoredHeader(NULL,reply_head->key[i],reply_head->val[i])))
  493.       {
  494.        if(censor!=reply_head->val[i])
  495.          {
  496.           PrintMessage(Debug,"CensorReplyHeader replaced '%s: %s' by '%s: %s'.",reply_head->key[i],reply_head->val[i],reply_head->key[i],censor);
  497.           reply_head->size+=strlen(censor)-strlen(reply_head->val[i]);
  498.           free(reply_head->val[i]);
  499.           reply_head->val[i]=censor;
  500.          }
  501.       }
  502.     else
  503.       {
  504.        PrintMessage(Debug,"CensorReplyHeader removed '%s: %s'.",reply_head->key[i],reply_head->val[i]);
  505.        RemoveFromHeader(reply_head,reply_head->key[i],reply_head->val[i]);
  506.       }
  507.    }
  508. }
  509. /*++++++++++++++++++++++++++++++++++++++
  510.   Create a new Header structure.
  511.   Header *CreateHeader Returns the new header structure.
  512.   char *line The top line in the original header.
  513.   int type The type of header, request=1, reply=0;
  514.   ++++++++++++++++++++++++++++++++++++++*/
  515. Header *CreateHeader(char *line,int type)
  516. {
  517.  Header *new=(Header*)malloc(sizeof(*new));
  518.  char *p=(char*)malloc(strlen(line)+1),*oldp=p;
  519.  char *method="",*url="",*note="",*version="";
  520.  int status=0;
  521.  /* Parse the original header. */
  522.  strcpy(p,line);
  523.  new->type=type;
  524.  if(type==1)
  525.    {
  526.                                 /* GET http://www/xxx HTTP/1.0rn */
  527.     method=p;
  528.     while(*p && !isspace(*p))   /*    ^                            */
  529.        p++;
  530.     if(!*p) goto eol_req;
  531.     *p++=0;
  532.     while(*p && isspace(*p))    /*     ^                           */
  533.        p++;
  534.     if(!*p) goto eol_req;
  535.     url=p;
  536.     while(*p && !isspace(*p))   /*                   ^             */
  537.        p++;
  538.     if(!*p) goto eol_req;
  539.     *p++=0;
  540.     while(*p && isspace(*p))    /*                    ^            */
  541.        p++;
  542.     if(!*p) goto eol_req;
  543.     version=p;
  544.     while(*p && !isspace(*p))   /*                            ^    */
  545.        p++;
  546.     *p=0;
  547.    eol_req:
  548.     if(!*version)
  549.        version="HTTP/1.0";
  550.     new->method=(char*)malloc(strlen(method)+1);
  551.     strcpy(new->method,method);
  552.     new->url=(char*)malloc(strlen(url)+1);
  553.     strcpy(new->url,url);
  554.     for(p=new->method;*p;p++)
  555.        *p=toupper(*p);
  556.     new->status=0;
  557.     new->note=NULL;
  558.     new->size=strlen(new->method)+strlen(new->url);
  559.    }
  560.  else
  561.    {
  562.                                 /* HTTP/1.1 200 OK or somethingrn */
  563.     version=p;
  564.     while(*p && !isspace(*p))   /*         ^                        */
  565.        p++;
  566.     if(!*p) goto eol_rep;
  567.     *p++=0;
  568.     while(*p && isspace(*p))    /*          ^                       */
  569.        p++;
  570.     if(!*p) goto eol_rep;
  571.     status=atoi(p);
  572.     while(*p && !isspace(*p))   /*             ^                    */
  573.        p++;
  574.     if(!*p) goto eol_rep;
  575.     *p++=0;
  576.     while(*p && isspace(*p))    /*              ^                   */
  577.        p++;
  578.     if(!*p) goto eol_rep;
  579.     note=p;
  580.     while(*p && !iscntrl(*p))   /*                             ^    */
  581.        p++;
  582.     *p=0;
  583.    eol_rep:
  584.     new->method=NULL;
  585.     new->url=NULL;
  586.     new->status=status%1000;
  587.     new->note=(char*)malloc(strlen(note)+1);
  588.     strcpy(new->note,note);
  589.     new->size=strlen(new->note)+3; /* 3 = strlen(status) */
  590.    }
  591.  new->version=(char*)malloc(strlen(version)+1);
  592.  strcpy(new->version,version);
  593.  for(p=new->version;*p;p++)
  594.     *p=toupper(*p);
  595.  new->size+=strlen(new->version)+4; /* 4 = 2*' ' + 'rn' */
  596.  new->size+=2; /* 2 = 'rn' */
  597.  new->n=0;
  598.  new->key=NULL;
  599.  new->val=NULL;
  600.  free(oldp);
  601.  return(new);
  602. }
  603. /*++++++++++++++++++++++++++++++++++++++
  604.   Add a specified key and value to the header structure.
  605.   Header *head The header structure to add to.
  606.   char *key The key to add.
  607.   char *val The value to add.
  608.   ++++++++++++++++++++++++++++++++++++++*/
  609. void AddToHeader(Header *head,char *key,char *val)
  610. {
  611.  int i;
  612.  head->size+=strlen(key)+strlen(val)+4;
  613.  if(head->key)
  614.     for(i=0;i<head->n;i++)
  615.        if(!head->key[i])
  616.          {
  617.           head->key[i]=(char*)malloc(strlen(key)+1);
  618.           strcpy(head->key[i],key);
  619.           head->val[i]=(char*)malloc(strlen(val)+1);
  620.           strcpy(head->val[i],val);
  621.           return;
  622.          }
  623.  if(head->key)
  624.    {
  625.     head->key=(char**)realloc((void*)head->key,sizeof(char*)*(head->n+1));
  626.     head->val=(char**)realloc((void*)head->val,sizeof(char*)*(head->n+1));
  627.    }
  628.  else
  629.    {
  630.     head->key=(char**)malloc(sizeof(char*)*8);
  631.     head->val=(char**)malloc(sizeof(char*)*8);
  632.    }
  633.  head->key[head->n]=(char*)malloc(strlen(key)+1);
  634.  strcpy(head->key[head->n],key);
  635.  head->val[head->n]=(char*)malloc(strlen(val)+1);
  636.  strcpy(head->val[head->n],val);
  637.  head->n++;
  638. }
  639. /*++++++++++++++++++++++++++++++++++++++
  640.   Add a raw line to a header.
  641.   int AddToHeaderRaw Returns 1 if OK, else 0.
  642.   Header *head The header to add the line to.
  643.   char *line The raw line of data.
  644.   ++++++++++++++++++++++++++++++++++++++*/
  645. static int AddToHeaderRaw(Header *head,char *line)
  646. {
  647.  char *key,*val,*r=line+strlen(line)-1;
  648.  /* trim line */
  649.  while(r>line && isspace(*r))
  650.     r--;
  651.  /* last line */
  652.  if(r==line)
  653.     return(0);
  654.  /* split line */
  655.  key=line;
  656.  val=line;
  657.  while(*val && *val!=':')
  658.     val++;
  659.  if(!*val)
  660.     return(0);
  661.  *++r=0;
  662.  *val++=0;
  663.  while(*val && isspace(*val))
  664.     val++;
  665.  /* Add to the header */
  666.  AddToHeader(head,key,val);
  667.  return(1);
  668. }
  669. /*++++++++++++++++++++++++++++++++++++++
  670.   Remove the specified key and value pair from a header structure.
  671.   Header *head The header to remove from.
  672.   char* key The key to look for and remove.
  673.   char *val The value to look for and remove.
  674.   ++++++++++++++++++++++++++++++++++++++*/
  675. void RemoveFromHeader(Header *head,char* key,char *val)
  676. {
  677.  int i;
  678.  for(i=0;i<head->n;i++)
  679.    {
  680.     if(!head->key[i])
  681.        continue;
  682.     if(!strcasecmp(head->key[i],key) &&
  683.        (!val || !strncasecmp(head->val[i],val,strlen(val))))
  684.       {
  685.        head->size-=strlen(head->key[i])+strlen(head->val[i])+4;
  686.        free(head->key[i]);
  687.        head->key[i]=NULL;
  688.        free(head->val[i]);
  689.        head->val[i]=NULL;
  690.       }
  691.    }
  692. }
  693. /*++++++++++++++++++++++++++++++++++++++
  694.   Search through a HTTP header for a specified key and value pair.
  695.   char *GetHeader Returns the value for the header key or NULL if none.
  696.   Header *head The header to search through.
  697.   char* key The key to look for.
  698.   char *val The value to look for.
  699.   ++++++++++++++++++++++++++++++++++++++*/
  700. char *GetHeader(Header *head,char* key,char *val)
  701. {
  702.  int i;
  703.  for(i=0;i<head->n;i++)
  704.    {
  705.     if(!head->key[i])
  706.        continue;
  707.     if(!strcasecmp(head->key[i],key) &&
  708.        (!val || !strncasecmp(head->val[i],val,strlen(val))))
  709.        return(head->val[i]);
  710.    }
  711.  return(NULL);
  712. }
  713. /*++++++++++++++++++++++++++++++++++++++
  714.   Return a string that contains the whole of the header.
  715.   char *HeaderString Returns the header as a string.
  716.   Header *head The header structure to convert.
  717.   ++++++++++++++++++++++++++++++++++++++*/
  718. char *HeaderString(Header *head)
  719. {
  720.  char *str;
  721.  int i;
  722.  str=(char*)malloc(head->size+16);
  723.  if(head->type==1)
  724.    {
  725.     strcpy(str,head->method);
  726.     strcat(str," ");
  727.     strcat(str,head->url);
  728.     strcat(str," ");
  729.     strcat(str,head->version);
  730.    }
  731.  else
  732.    {
  733.     if(*head->version)
  734.       {
  735.        strcpy(str,head->version);
  736.        strcat(str," ");
  737.        sprintf(str+strlen(head->version)+1,"%3d",head->status);
  738.        strcat(str," ");
  739.        strcat(str,head->note);
  740.       }
  741.     else
  742.        strcpy(str,"HTTP/1.0 200 OK");
  743.    }
  744.  strcat(str,"rn");
  745.  for(i=0;i<head->n;i++)
  746.    {
  747.     if(!head->key[i])
  748.        continue;
  749.     strcat(str,head->key[i]);
  750.     strcat(str,": ");
  751.     strcat(str,head->val[i]);
  752.     strcat(str,"rn");
  753.    }
  754.  strcat(str,"rn");
  755.  return(str);
  756. }
  757. /*++++++++++++++++++++++++++++++++++++++
  758.   Free a header structure.
  759.   Header *head The header structure to free.
  760.   ++++++++++++++++++++++++++++++++++++++*/
  761. void FreeHeader(Header *head)
  762. {
  763.  int i;
  764.  if(head->type)
  765.    {
  766.     free(head->method);
  767.     free(head->url);
  768.    }
  769.  else
  770.     free(head->note);
  771.  free(head->version);
  772.  for(i=0;i<head->n;i++)
  773.    {
  774.     if(!head->key[i])
  775.        continue;
  776.     free(head->key[i]);
  777.     free(head->val[i]);
  778.    }
  779.  if(head->n)
  780.    {
  781.     free(head->key);
  782.     free(head->val);
  783.    }
  784.  free(head);
  785. }
  786. /*++++++++++++++++++++++++++++++++++++++
  787.   Create a new Body structure.
  788.   Header *CreateBody Returns the new body structure.
  789.   int length The length of the body;
  790.   ++++++++++++++++++++++++++++++++++++++*/
  791. Body *CreateBody(int length)
  792. {
  793.  Body *new=(Body*)malloc(sizeof(*new));
  794.  new->length=length;
  795.  new->content=malloc(length+3);
  796.  return(new);
  797. }
  798. /*++++++++++++++++++++++++++++++++++++++
  799.   Free a body structure.
  800.   Body *body The body structure to free.
  801.   ++++++++++++++++++++++++++++++++++++++*/
  802. void FreeBody(Body *body)
  803. {
  804.  if(body->content)
  805.     free(body->content);
  806.  free(body);
  807. }