Branch: Tag:

2000-10-17

2000-10-17 21:01:34 by Per Hedbor <ph@opera.com>

Fixes [Bug 370 (#370)]

Rev: server/etc/modules/Variable.pmod/Image.pike:1.1
Rev: server/etc/modules/Variable.pmod/Upload.pike:1.1
Rev: server/modules/tags/vform.pike:1.13
Rev: server/protocols/http.pike:1.281

2:   // Modified by Francesco Chemolli to add throttling capabilities.   // Copyright © 1996 - 2000, Roxen IS.    - constant cvs_version = "$Id: http.pike,v 1.280 2000/10/07 11:22:03 per Exp $"; + constant cvs_version = "$Id: http.pike,v 1.281 2000/10/17 21:01:34 per Exp $";   // #define REQUEST_DEBUG   #define MAGIC_ERROR   
710:   }       - #if constant(Roxen.HeaderParser) +    static Roxen.HeaderParser hp = Roxen.HeaderParser(); - #endif + static function(string:array(string|mapping)) hpf = hp->feed;   int last; -  +    private int parse_got( string new_data )   {    multiset (string) sup;    string a, b, s="", linename, contents; -  mapping header_mapping = ([]); +     - #if constant(Roxen.HeaderParser) +     if( !method )    {    array res; -  if( catch { res = hp->feed( new_data ); } ) -  return 1; +  while( strlen( new_data ) ) +  { +  string q; +  if( strlen( new_data ) > 4192 ) +  q = new_data[..4191]; +  else +  { +  q = new_data; +  new_data = ""; +  } +  if( catch { res = hpf( q ); } ) return 1; +  if( res && strlen( new_data = new_data[4192..] ) ) +  { +  res[0] += new_data; +  break; +  } +  }    if( !res )    return 0; // Not enough data; -  /* now in res: +     -  +  /* +  now in res:    leftovers/data -  +     first line    headers    */    data = res[0];    line = res[1]; -  header_mapping = res[2]; +  request_headers = res[2];    } - #else -  REQUEST_WERR(sprintf("HTTP: parse_got(%O)", raw)); -  if (!method) { // Haven't parsed the first line yet. -  int start; -  // We check for \n only if \r\n fails, since Netscape 4.5 sends -  // just a \n when doing a proxy-request. -  // example line: -  // "CONNECT mikabran:443 HTTP/1.0\n" -  // "User-Agent: Mozilla/4.5 [en] (X11; U; Linux 2.0.35 i586)" -  // Die Netscape, die! *grumble* -  // Luckily the solution below shouldn't ever cause any slowdowns -  // -  // Note by Neo: Rewrote the sscanf code to use search with a memory. -  // The reason is that otherwise it's really, REALLY easy to lock up -  // a Roxen server by sending a request that either has no newlines at all -  // or has infinite sized headers. With this version, Roxen doesn't die but -  // it does suck up data ad finitum - a configurable max GET request size and -  // also a max GET+headers would be nice. -  -  if((start = search(raw[last..], "\n")) == -1) { -  last = max(strlen(raw) - 3, 4); -  REQUEST_WERR(sprintf("HTTP: parse_got(%O): Not enough data.", raw)); -  return 0; -  } else { -  start += last; -  last = 0; -  if(!start) { -  REQUEST_WERR(sprintf("HTTP: parse_got(%O): malformed request.", raw)); -  return 1; // malformed request -  } -  } -  if (raw[start-1] == '\r') { -  line = raw[..start-2]; -  } else { -  // Kludge for Netscape 4.5 sending bad requests. -  line = raw[..start-1]; -  } -  if(strlen(line) < 4) -  { -  // Incorrect request actually - min possible (HTTP/0.9) is "GET /" -  // but need to support PING of course! -  -  REQUEST_WERR(sprintf("HTTP: parse_got(%O): Malformed request.", raw)); -  return 1; -  } - #endif +     string trailer, trailer_trailer;       switch(sscanf(line+" ", "%s %s %s %s %s",    method, f, clientprot, trailer, trailer_trailer))    {    case 5: -  // Stupid sscanf! +     if (trailer_trailer != "") {    // Get rid of the extra space from the sscanf above.    trailer += " " + trailer_trailer[..sizeof(trailer_trailer)-2];
826:    prot = "HTTP/1.1";    }    // Do we have all the headers? -  if ((end = search(raw[last..], "\r\n\r\n")) == -1) { -  // No, we still need more data. -  REQUEST_WERR("HTTP: parse_got(): Request is still not complete."); -  last = max(strlen(raw) - 5, 0); -  return 0; -  } -  end += last; -  last = 0; -  data = raw[end+4..]; -  s = raw[sizeof(line)+2..end-1]; + // if ((end = search(raw[last..], "\r\n\r\n")) == -1) { + // // No, we still need more data. + // REQUEST_WERR("HTTP: parse_got(): Request is still not complete."); + // last = max(strlen(raw) - 5, 0); + // return 0; + // } + // end += last; + // last = 0; + // data = raw[end+4..]; + // s = raw[sizeof(line)+2..end-1];    // s now contains the unparsed headers.    break;   
858:    // Too many or too few entries -> Hum.    return 1;    } - #if !constant(Roxen.HeaderParser) -  } -  else -  { -  // HTTP/1.0 or later -  // Check that the request is complete -  int end; -  if ((end = search(raw[last..], "\r\n\r\n")) == -1) { -  // No, we still need more data. -  REQUEST_WERR("HTTP: parse_got(): Request is still not complete."); -  last = max(strlen(raw) - 5, 0); -  return 0; -  } -  end += last; -  data = raw[end+4..]; -  s = raw[sizeof(line)+2..end-1]; -  } - #endif +     if(method == "PING")    {    my_fd->write("PONG\r\n");    return 2;    }    REQUEST_WERR(sprintf("***** req line: %O", line)); -  REQUEST_WERR(sprintf("***** headers: %O", s)); -  REQUEST_WERR(sprintf("***** data: %O", data)); +  REQUEST_WERR(sprintf("***** headers: %O", request_headers)); +  REQUEST_WERR(sprintf("***** data (%d):%O", strlen(data),data));    raw_url = f;    time = _time(1);    // if(!data) data = "";
903:    }    }    - #if constant(Roxen.HeaderParser) -  request_headers = header_mapping; -  foreach( (array)header_mapping, [string linename, array|string contents] ) - #else -  request_headers = ([]); -  foreach(s/"\r\n" - ({""}), line) -  if(sscanf(line, "%s:%*[ \t]%s", linename, contents) == 3) -  { -  linename=lower_case(linename); -  request_headers[linename] = contents; - #endif +  foreach( (array)request_headers, [string linename, array|string contents] )    switch (linename)    {    case "pragma": pragma|=(multiset)((contents-" ")/","); break;
971:   // }   // }    } - #if !constant(Roxen.HeaderParser) -  } - #endif +     if(misc->len && method == "POST")    {    if(!data) data="";
1035:    variables[part->disp_params->name] = part->getdata();    }    } + // werror("%O\n", variables );    break;    }    }
1827:    misc->connection = "close";    }    - #if constant( Roxen.make_http_headers ) +     head_string += Roxen.make_http_headers( heads ); - #else -  foreach(indices(heads), h) -  if(arrayp(heads[h])) -  foreach(heads[h], tmp) -  head_string += h+": "+tmp+"\r\n"; -  else -  head_string += h+": "+heads[h]+"\r\n"; -  head_string += "\r\n"; - #endif +     if( strlen( charset ) )    head_string = output_encode( head_string )[1];    conf->hsent += strlen(head_string);
2005:       if(wanted_data)    { +  data += s;    if(strlen(s) + have_data < wanted_data)    {    // cache += ({ s });