home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Magazine / wwwoffle-2.1.tar.gz / wwwoffle-2.1 / parse.c < prev    next >
C/C++ Source or Header  |  1998-02-12  |  11KB  |  501 lines

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/parse.c 2.20 1998/02/12 19:10:24 amb Exp $
  3.  
  4.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.1.
  5.   Functions to parse the HTTP requests.
  6.   ******************/ /******************
  7.   Written by Andrew M. Bishop
  8.  
  9.   This file Copyright 1996,97,98 Andrew M. Bishop
  10.   It may be distributed under the GNU Public License, version 2, or
  11.   any higher version.  See section COPYING of the GNU Public license
  12.   for conditions under which this file may be redistributed.
  13.   ***************************************/
  14.  
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20.  
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <time.h>
  24. #include <unistd.h>
  25.  
  26. #include "wwwoffle.h"
  27. #include "misc.h"
  28. #include "proto.h"
  29. #include "errors.h"
  30. #include "config.h"
  31.  
  32.  
  33. /*++++++++++++++++++++++++++++++++++++++
  34.   Parse the request to the server.
  35.  
  36.   char *ParseRequest Returns the URL or NULL if it failed.
  37.  
  38.   int fd The file descriptor to read the request from.
  39.  
  40.   char **request_head Return the header of the request.
  41.  
  42.   char **request_body Return the body of the request.
  43.   ++++++++++++++++++++++++++++++++++++++*/
  44.  
  45. char *ParseRequest(int fd,char **request_head,char **request_body)
  46. {
  47.  char *url=NULL,*line=NULL;
  48.  int length=-1;
  49.  
  50.  *request_head=NULL;
  51.  *request_body=NULL;
  52.  
  53.  while((line=read_line_or_timeout(fd,line)))
  54.    {
  55.     if(!strncmp("Content-length:",line,15) || !strncmp("Content-Length:",line,15))
  56.        length=atoi(&line[15]);
  57.  
  58.     if(!*request_head)          /* first line */
  59.       {
  60.        *request_head=(char*)malloc(strlen(line)+1);
  61.        strcpy(*request_head,line);
  62.  
  63.        url=(char*)malloc(strlen(line));
  64.        if(sscanf(line,"%*s %s",url)!=1)
  65.          {free(url);return(NULL);}
  66.       }
  67.     else
  68.       {
  69.        *request_head=(char*)realloc((void*)*request_head,strlen(line)+strlen(*request_head)+1);
  70.        strcat(*request_head,line);
  71.       }
  72.  
  73.     if(*line=='\r' || *line=='\n')
  74.        break;
  75.    }
  76.  
  77.  if(!*request_head)
  78.     return(NULL);
  79.  
  80.  if(line)
  81.     free(line);
  82.  
  83.  if(!strncasecmp("POST",*request_head,4))
  84.    {
  85.     if(length==-1)
  86.       {free(url);return(NULL);}
  87.  
  88.     if(length)
  89.       {
  90.        int m,l=length;
  91.  
  92.        *request_body=(char*)malloc(length+1);
  93.  
  94.        do
  95.          {
  96.           m=read_data_or_timeout(fd,&(*request_body)[length-l],l);
  97.          }
  98.        while(m>0 && (l-=m));
  99.  
  100.        if(l)
  101.          {free(url);return(NULL);}
  102.  
  103.        (*request_body)[length]=0;
  104.       }
  105.  
  106.     url=(char*)realloc((void*)url,strlen(url)+32);
  107.  
  108.     if(strchr(url,'?'))
  109.       {
  110.        char *from=url+strlen(url),*to=from+1;
  111.        while(*from!='?')
  112.           *to--=*from--;
  113.        *to='!';
  114.       }
  115.     else
  116.        strcat(url,"?");
  117.  
  118.     sprintf(url+strlen(url),"!POST:%s",MakeHash(*request_body));
  119.    }
  120.  
  121.  return(url);
  122. }
  123.  
  124.  
  125. /*++++++++++++++++++++++++++++++++++++++
  126.   Modify the request to ask for changes since the spooled file.
  127.  
  128.   int RequestChanges Returns 1 if the file needs changes made, 0 if not, or -1 in case of an error.
  129.  
  130.   int fd The file descriptor of the spooled file.
  131.  
  132.   char **request_head The head of the HTTP request to modify.
  133.   ++++++++++++++++++++++++++++++++++++++*/
  134.  
  135. int RequestChanges(int fd,char **request_head)
  136. {
  137.  struct stat buf;
  138.  char *reply;
  139.  int status=0;
  140.  
  141.  reply=read_line(fd,NULL);
  142.  
  143.  if(reply)
  144.    {
  145.     sscanf(reply,"%*s %d",&status);
  146.     free(reply);
  147.    }
  148.  
  149.  if(status==0)
  150.    {
  151.     PrintMessage(Debug,"Empty or no status");
  152.     return(-1);
  153.    }
  154.  else if(status>=200 && status<400 && !fstat(fd,&buf))
  155.    {
  156.     if((time(NULL)-buf.st_mtime)<RequestChanged)
  157.       {
  158.        PrintMessage(Debug,"Too new");
  159.        return(0);
  160.       }
  161.     else
  162.       {
  163.        char *if_mod=(char*)malloc(64);
  164.        char *copy=(char*)malloc(strlen(*request_head)+64);
  165.        char *eol=strchr(*request_head,'\n');
  166.  
  167.        sprintf(if_mod,"If-Modified-Since: %s",RFC822Date(buf.st_mtime,1));
  168.        if_mod[strlen(if_mod)-1]=0;
  169.        *eol=0; eol++;
  170.  
  171.        strcpy(copy,*request_head);
  172.        strcat(copy,"\n");
  173.        strcat(copy,if_mod);
  174.        strcat(copy,"\r\n");
  175.        strcat(copy,eol);
  176.  
  177.        free(*request_head);
  178.        free(if_mod);
  179.  
  180.        *request_head=copy;
  181.       }
  182.    }
  183.  
  184.  return(1);
  185. }
  186.  
  187.  
  188. /*++++++++++++++++++++++++++++++++++++++
  189.   Return the location that the URL has been moved to.
  190.  
  191.   char *MovedLocation Returns the new URL.
  192.  
  193.   URL *Url The original URL.
  194.  
  195.   char *reply_head The head of the original HTTP reply.
  196.   ++++++++++++++++++++++++++++++++++++++*/
  197.  
  198. char *MovedLocation(URL *Url,char *reply_head)
  199. {
  200.  char *location,*eol,oldeol;
  201.  char *new;
  202.  
  203.  location=strstr(reply_head,"\nLocation:");
  204.  if(!location)
  205.     return(NULL);
  206.  
  207.  location+=11;
  208.  eol=strchr(location,'\n');
  209.  if(eol[-1]=='\r')
  210.     eol--;
  211.  oldeol=*eol;
  212.  *eol=0;
  213.  
  214.  new=(char*)malloc(strlen(location)+strlen(Url->name));
  215.  
  216.  if(!strchr(location,'/'))
  217.    {
  218.     char *newpath=(char*)malloc(strlen(Url->path)+1),*p;
  219.     strcpy(newpath,Url->path);
  220.     p=newpath+strlen(newpath);
  221.     while(p>newpath && *--p!='/')
  222.        *p=0;
  223.     sprintf(new,"%s://%s/%s%s",Url->proto,Url->host,newpath,location);
  224.     free(newpath);
  225.    }
  226.  else if(*location=='/')
  227.     sprintf(new,"%s://%s%s",Url->proto,Url->host,location);
  228.  else
  229.     strcpy(new,location);
  230.  
  231.  *eol=oldeol;
  232.  
  233.  return(new);
  234. }
  235.  
  236.  
  237. /*++++++++++++++++++++++++++++++++++++++
  238.   Create a new request for a page.
  239.  
  240.   char *RequestURL Ask for a page.
  241.  
  242.   char *url The URL to get.
  243.  
  244.   char *referer The Refering URL or NULL if none.
  245.   ++++++++++++++++++++++++++++++++++++++*/
  246.  
  247. char *RequestURL(char *url,char *referer)
  248. {
  249.  char *new=(char*)malloc(strlen(url)+(referer?strlen(referer):0)+64);
  250.  
  251.  sprintf(new,"GET %s HTTP/1.0\r\n",url);
  252.  if(referer)
  253.     sprintf(&new[strlen(new)],"Referer: %s\r\n",referer);
  254.  strcat(new,"Accept: */*\r\n"
  255.             "\r\n");
  256.  
  257.  return(new);
  258. }
  259.  
  260.  
  261. /*++++++++++++++++++++++++++++++++++++++
  262.   Modify the request taking into account censoring of header and modified URL.
  263.  
  264.   char *ModifyRequest Return the new request.
  265.  
  266.   URL *Url The actual URL.
  267.  
  268.   char *request_head The original head of the HTTP request possibly with a different URL.
  269.   ++++++++++++++++++++++++++++++++++++++*/
  270.  
  271. char *ModifyRequest(URL *Url,char *request_head)
  272. {
  273.  char *new;
  274.  char *hostheader=(char*)malloc(strlen(Url->host)+16),*closeheader;
  275.  char *bol,*to,http[16];
  276.  
  277.  /* Make up the new headers. */
  278.  
  279.  sprintf(hostheader,"Host: %s\r\n",Url->host);
  280.  closeheader="Connection: close\r\n";
  281.  
  282.  new=(char*)malloc(strlen(request_head)+strlen(closeheader)+strlen(hostheader)+strlen(Url->name));
  283.  
  284.  /* Parse the old header and create a new one. */
  285.  
  286.  sscanf(request_head,"%s %*s %s",new,http);
  287.  strcat(new," ");
  288.  strcat(new,Url->name);
  289.  
  290.  /* Remove the false arguments from POSTed URLs. */
  291.  
  292.  if(!strncasecmp(new,"POST",4))
  293.    {
  294.     char *pling=strstr(new,"?!");
  295.     char *pling2=strchr(++pling+1,'!');
  296.  
  297.     if(pling2)
  298.        for(;pling<pling2;pling++)
  299.           *pling=*(pling+1);
  300.  
  301.     *(pling-1)=0;
  302.    }
  303.  
  304.  strcat(new," ");
  305.  strcat(new,http);
  306.  strcat(new,"\r\n");
  307.  
  308.  strcat(new,hostheader);
  309.  
  310.  /* Check for HTTP 1.1 and add a Connection header */
  311.  
  312.  if(!strncmp(http,"HTTP/1.1",8))
  313.     strcat(new,closeheader);
  314.  
  315.  /* Censor the header */
  316.  
  317.  to=new+strlen(new);
  318.  bol=strchr(request_head,'\n')+1;
  319.  
  320.  while(*bol)
  321.    {
  322.     if(!strncmp("Host:",bol,5) || !strncmp("Connection:",bol,11) || !strncmp("Proxy-Connection:",bol,17))
  323.        bol=strchr(bol,'\n');
  324.     else if(IsCensoredHeader(bol))
  325.       {
  326.        char *eol=strchr(bol,'\n');
  327.  
  328.        if(*(eol-1)=='\r')
  329.           *(eol-1)=0;
  330.        else
  331.           *eol=0;
  332.  
  333.        PrintMessage(Debug,"Censored '%s'",bol);
  334.  
  335.        bol=eol;
  336.       }
  337.     else if(!strncmp("Referer:",bol,8))
  338.       {
  339.        char *eol=strchr(bol,'\n');
  340.        char *pling=strstr(bol,"?!");
  341.  
  342.        if(*(eol-1)=='\r')
  343.           *(eol-1)=0;
  344.        else
  345.           *eol=0;
  346.  
  347.        if(pling)
  348.          {
  349.           char *pling2=strchr(++pling+1,'!');
  350.  
  351.           if(pling2)
  352.              for(;pling<pling2;pling++)
  353.                 *pling=*(pling+1);
  354.  
  355.           *(pling-1)=0;
  356.          }
  357.  
  358.        while(*bol)
  359.           *to++=*bol++;
  360.        *to++='\r';
  361.        *to++='\n';
  362.  
  363.        bol=eol;
  364.       }
  365.     else
  366.       {
  367.        while(*bol && *bol!='\n')
  368.           *to++=*bol++;
  369.        *to++=*bol;
  370.       }
  371.  
  372.     bol++;
  373.    }
  374.  
  375.  *to=0;
  376.  
  377.  /* tidy up and exit. */
  378.  
  379.  free(hostheader);
  380.  free(request_head);
  381.  
  382.  return(new);
  383. }
  384.  
  385.  
  386. /*++++++++++++++++++++++++++++++++++++++
  387.   Change the request to one that contains an authorisation string if required.
  388.  
  389.   char *MakeRequestAuthorised Returns a new request with the authorisation if required or else the old request.
  390.  
  391.   char *proxy The name of the proxy.
  392.  
  393.   char *request_head The old HTTP request head.
  394.   ++++++++++++++++++++++++++++++++++++++*/
  395.  
  396. char *MakeRequestAuthorised(char *proxy,char *request_head)
  397. {
  398.  char *new=request_head;
  399.  char *userpass=WhatProxyAuth(proxy);
  400.  
  401.  if(userpass)
  402.    {
  403.     char *userpassencoded=Base64Encode(userpass,strlen(userpass));
  404.     char *auth=(char*)malloc(strlen(userpassencoded)+32);
  405.     char *bol,*eol;
  406.  
  407.     sprintf(auth,"Proxy-Authorization: Basic %s\r\n",userpassencoded);
  408.  
  409.     new=(char*)malloc(strlen(request_head)+strlen(auth)+1);
  410.  
  411.     if((bol=strstr(request_head,"\nProxy-Authorization:")))
  412.        eol=strchr(++bol,'\n')+1;
  413.     else
  414.        bol=eol=strchr(request_head,'\n')+1;
  415.  
  416.     strncpy(new,request_head,bol-request_head);
  417.     new[bol-request_head]=0;
  418.     strcat(new,auth);
  419.     strcat(new,eol);
  420.  
  421.     free(auth);
  422.    }
  423.  
  424.  return(new);
  425. }
  426.  
  427.  
  428. /*++++++++++++++++++++++++++++++++++++++
  429.   Change the request from one to a proxy to a normal one.
  430.  
  431.   char *MakeRequestNonProxy Return a new request that is suitable for a non-proxy server.
  432.  
  433.   char *request_head The buffer containing the head of the HTTP request.
  434.   ++++++++++++++++++++++++++++++++++++++*/
  435.  
  436. char *MakeRequestNonProxy(char *request_head)
  437. {
  438.  char *new=(char*)malloc(strlen(request_head)),*r=request_head,*n=new;
  439.  
  440.  /* The URL is already in canonical form because of the ModifyRequest() function. */
  441.  
  442.  while(*r!=' ')                 /* 'GET ' */
  443.     *n++=*r++;
  444.  *n++=*r++;
  445.  
  446.  while(*r!=':')                 /* 'http://' */
  447.     r++;
  448.  r+=3;
  449.  
  450.  while(*r!='/')                 /* 'www.host.domain/' */
  451.     r++;
  452.  
  453.  strcpy(n,r);
  454.  
  455.  return(new);
  456. }
  457.  
  458.  
  459. /*++++++++++++++++++++++++++++++++++++++
  460.   Parse the reply from the server.
  461.  
  462.   int ParseReply Return the numeric status of the reply.
  463.  
  464.   URL *Url The URL that we are reading.
  465.  
  466.   char *reply_head Return the head of the HTTP reply.
  467.   ++++++++++++++++++++++++++++++++++++++*/
  468.  
  469. int ParseReply(URL *Url,char **reply_head)
  470. {
  471.  char *line=NULL;
  472.  int status=0;
  473.  
  474.  *reply_head=NULL;
  475.  
  476.  while((line=(Url->Protocol->readhead)(line)))
  477.    {
  478.     if(!*reply_head)
  479.       {
  480.        *reply_head=(char*)malloc(strlen(line)+1);
  481.        strcpy(*reply_head,line);
  482.       }
  483.     else
  484.       {
  485.        *reply_head=(char*)realloc((void*)*reply_head,strlen(line)+strlen(*reply_head)+1);
  486.        strcat(*reply_head,line);
  487.       }
  488.  
  489.     if(*line=='\r' || *line=='\n')
  490.        break;
  491.    }
  492.  
  493.  if(!line)
  494.    return(0);
  495.  
  496.  if(sscanf(*reply_head,"%*s %d",&status)!=1)
  497.     status=0;
  498.  
  499.  return(status);
  500. }
  501.