0576d52002-10-22Martin Nilsson // This is a ChiliMoon protocol module.
199d031999-09-05Francesco Chemolli // Modified by Francesco Chemolli to add throttling capabilities.
50c4c42001-08-23Martin Nilsson // Copyright © 1996 - 2001, Roxen IS.
6a409d1999-12-27Martin Nilsson 
01ee532004-05-27Stephen R. van den Berg constant cvs_version = "$Id: http.pike,v 1.402 2004/05/27 17:16:06 _cvs_stephen Exp $";
a3ebea2000-08-12Per Hedbor // #define REQUEST_DEBUG
86e77d1998-05-07Per Hedbor #define MAGIC_ERROR
2a2a5b1996-12-01Per Hedbor // HTTP protocol module.
b1fca01996-11-12Per Hedbor #include <config.h>
9c19002001-02-27Per Hedbor #define TIMER_PREFIX "http:" #include <timers.h>
26f44e2000-08-13Per Hedbor 
3f6e4b2002-02-06Martin Stjernholm inherit RequestID;
ebb1c51998-02-24Per Hedbor #ifdef PROFILE
c5e0961999-10-04Per Hedbor #define HRTIME() gethrtime()
8afc811998-02-04Per Hedbor int req_time = HRTIME();
ebb1c51998-02-24Per Hedbor #endif
c5e0961999-10-04Per Hedbor 
cbe6c62000-03-18Martin Stjernholm #ifdef ID_OBJ_DEBUG
f9531d2004-04-04Martin Nilsson RoxenDebug.ObjectMarker __marker = RoxenDebug.ObjectMarker(this);
cbe6c62000-03-18Martin Stjernholm #endif
aa92c11998-08-20Henrik Grubbström (Grubba) #ifdef REQUEST_DEBUG
41b77c1999-07-15David Hedbor int footime, bartime;
36160e2004-05-24Stephen R. van den Berg #define REQUEST_WERR(X) do {bartime = gethrtime()-footime; werror("%s (%d)\n", (X), bartime);footime=gethrtime();} while (0)
aa92c11998-08-20Henrik Grubbström (Grubba) #else
36160e2004-05-24Stephen R. van den Berg #define REQUEST_WERR(X) do {} while (0)
aa92c11998-08-20Henrik Grubbström (Grubba) #endif
3235691998-03-26Per Hedbor #ifdef FD_DEBUG
36160e2004-05-24Stephen R. van den Berg #define MARK_FD(X) do { \ int _fd = my_fd && my_fd->query_fd ? my_fd->query_fd() : -1; \ REQUEST_WERR("FD " + (_fd == -1 ? sprintf ("%O", my_fd) : _fd) + ": " + (X)); \ mark_fd(_fd, (X)+" "+remoteaddr); \ } while (0)
3235691998-03-26Per Hedbor #else
36160e2004-05-24Stephen R. van den Berg #define MARK_FD(X) do {} while (0)
3235691998-03-26Per Hedbor #endif
bdd3082000-05-14Francesco Chemolli #ifdef THROTTLING_DEBUG #undef THROTTLING_DEBUG #define THROTTLING_DEBUG(X) werror("Throttling: "+X+"\n") #else #define THROTTLING_DEBUG(X) #endif
f49bd32000-01-20Martin Nilsson constant decode = MIME.decode_base64;
86903b2003-01-23Martin Nilsson constant find_supports_and_vars = core.find_supports_and_vars; constant version = core.version; constant _query = core.query;
b1fca01996-11-12Per Hedbor 
7ee5651996-12-10Per Hedbor private static array(string) cache; private static int wanted_data, have_data;
7ed2732004-04-04Martin Nilsson private static String.Buffer data_buffer;
7ee5651996-12-10Per Hedbor 
36160e2004-05-24Stephen R. van den Berg private static multiset(string) none_match; int kept_alive; #ifdef DEBUG #define CHECK_FD_SAFE_USE do { \ if (this_thread() != roxen->backend_thread && \ (my_fd->query_read_callback() || my_fd->query_write_callback() || \ my_fd->query_close_callback() || \ !zero_type (find_call_out (do_timeout)))) \ error ("Got callbacks but not called from backend thread.\n"); \ } while (0) #else #define CHECK_FD_SAFE_USE do {} while (0) #endif
b1fca01996-11-12Per Hedbor #include <roxen.h> #include <module.h>
470ed72000-01-03Martin Nilsson #include <variables.h>
773ac62001-03-20Martin Stjernholm #include <request_trace.h> #define MY_TRACE_ENTER(A, B) \
f9531d2004-04-04Martin Nilsson  do {RequestID id = this; TRACE_ENTER (A, B);} while (0)
773ac62001-03-20Martin Stjernholm #define MY_TRACE_LEAVE(A) \
f9531d2004-04-04Martin Nilsson  do {RequestID id = this; TRACE_LEAVE (A);} while (0)
b1fca01996-11-12Per Hedbor 
ebe2582002-06-03Martin Nilsson mapping(string:array) real_variables = ([]);
5118342004-05-21Stephen R. van den Berg mapping(string:array) stash_body_parts = ([]);
5aca9b2001-09-28Martin Stjernholm mapping(string:mixed)|FakedVariables variables = FakedVariables( real_variables );
2fdf092000-12-02Per Hedbor 
59f65b2000-01-05Henrik Grubbström (Grubba) mapping (string:mixed) misc = ([ #ifdef REQUEST_DEBUG "trace_enter":lambda(mixed ...args) {
52e0822000-03-07Henrik Grubbström (Grubba)  REQUEST_WERR(sprintf("TRACE_ENTER(%{%O,%})", args));
59f65b2000-01-05Henrik Grubbström (Grubba)  }, "trace_leave":lambda(mixed ...args) {
52e0822000-03-07Henrik Grubbström (Grubba)  REQUEST_WERR(sprintf("TRACE_LEAVE(%{%O,%})", args));
59f65b2000-01-05Henrik Grubbström (Grubba)  }
338ffa2000-02-15Martin Nilsson #endif // REQUEST_DEBUG
59f65b2000-01-05Henrik Grubbström (Grubba) ]);
36160e2004-05-24Stephen R. van den Berg mapping (string:mixed) connection_misc = ([ ]);
8200cd1998-07-14Henrik Grubbström (Grubba) mapping (string:string) cookies = ([ ]); mapping (string:string) request_headers = ([ ]);
f49bd32000-01-20Martin Nilsson mapping (string:string) client_var = ([ ]);
b1fca01996-11-12Per Hedbor 
06d5331998-04-03Per Hedbor multiset (string) prestate = (< >); multiset (string) config = (< >);
ebb1c51998-02-24Per Hedbor multiset (string) pragma = (< >);
b1fca01996-11-12Per Hedbor 
beaca01998-02-20Per Hedbor mapping file;
b1fca01996-11-12Per Hedbor  string rest_query="";
26b0b92001-10-02Per Hedbor string raw="";
60a1a11998-08-03Henrik Grubbström (Grubba) string extra_extension = ""; // special hack for the language module
cf4a902001-01-19Per Hedbor  class AuthEmulator // Emulate the old (rather cumbersome) authentication API { mixed `[]( int i ) { User u; switch( i ) { case 0:
c659612004-05-24Martin Nilsson  return conf->authenticate( this );
cf4a902001-01-19Per Hedbor  case 1:
c659612004-05-24Martin Nilsson  if( u = conf->authenticate( this ) )
cf4a902001-01-19Per Hedbor  return u->name(); if( realauth ) return (realauth/":")[0]; case 2:
c659612004-05-24Martin Nilsson  if( u = conf->authenticate( this ) )
cf4a902001-01-19Per Hedbor  return 0; if( realauth ) return ((realauth/":")[1..])*":"; } } int `!( ) { return !realauth; } }
36160e2004-05-24Stephen R. van den Berg array|AuthEmulator auth;
b1fca01996-11-12Per Hedbor 
ed15161999-11-19Per Hedbor void decode_map( mapping what, function decoder ) {
4c9bdc2002-07-05Martin Nilsson  foreach( what; mixed q; mixed val )
ed15161999-11-19Per Hedbor  { string ni; if( stringp( q ) )
31c2ac2000-01-12Henrik Grubbström (Grubba)  catch { ni = decoder( q ); };
ed15161999-11-19Per Hedbor  if( stringp( val ) )
31c2ac2000-01-12Henrik Grubbström (Grubba)  catch { val = decoder( val ); };
ed15161999-11-19Per Hedbor  else if( arrayp( val ) ) val = map( val, lambda( mixed q ) { if( stringp( q ) )
31c2ac2000-01-12Henrik Grubbström (Grubba)  catch { return decoder( q ); };
ed15161999-11-19Per Hedbor  return q; } ); else if( mappingp( val ) ) decode_map( val, decoder ); else if( multisetp( val ) ) val = mkmultiset( map( indices(val), lambda( mixed q ) { if( stringp( q ) )
31c2ac2000-01-12Henrik Grubbström (Grubba)  catch { return decoder( q ); };
ed15161999-11-19Per Hedbor  return q; } )); what[ni] = val; if( q != ni ) m_delete( what, q ); } }
653d7d2000-02-14Per Hedbor void decode_charset_encoding( string|function(string:string) decoder )
ed15161999-11-19Per Hedbor {
36160e2004-05-24Stephen R. van den Berg  if( misc->request_charset_decoded ) return;
653d7d2000-02-14Per Hedbor  if(stringp(decoder))
a3ebea2000-08-12Per Hedbor  decoder = Roxen._charset_decoder(Locale.Charset.decoder(decoder))->decode;
36160e2004-05-24Stephen R. van den Berg  if( !decoder )
0b0d082000-02-14Per Hedbor  return;
653d7d2000-02-14Per Hedbor 
99cb5e2001-02-05Per Hedbor  misc->request_charset_decoded = 1;
31c2ac2000-01-12Henrik Grubbström (Grubba)  string safe_decoder(string s) { catch { return decoder(s); }; return s; }; if( prot ) prot = safe_decoder( prot ); if( clientprot ) clientprot = safe_decoder( clientprot ); if( method ) method = safe_decoder( method ); if( rest_query ) rest_query = safe_decoder( rest_query ); if( query ) query = safe_decoder( query ); if( not_query ) not_query = safe_decoder( not_query );
cf4a902001-01-19Per Hedbor  if( realauth )
ed15161999-11-19Per Hedbor  {
31c2ac2000-01-12Henrik Grubbström (Grubba)  rawauth = safe_decoder( rawauth ); realauth = safe_decoder( realauth );
ed15161999-11-19Per Hedbor  }
abdff21999-12-27Martin Nilsson  if( since )
31c2ac2000-01-12Henrik Grubbström (Grubba)  since = safe_decoder( since );
ed15161999-11-19Per Hedbor 
2fdf092000-12-02Per Hedbor  decode_map( real_variables, decoder );
ed15161999-11-19Per Hedbor  decode_map( misc, decoder ); decode_map( cookies, decoder ); decode_map( request_headers, decoder );
31c2ac2000-01-12Henrik Grubbström (Grubba) 
ed15161999-11-19Per Hedbor  if( client )
31c2ac2000-01-12Henrik Grubbström (Grubba)  client = map( client, safe_decoder );
ed15161999-11-19Per Hedbor  if( referer )
31c2ac2000-01-12Henrik Grubbström (Grubba)  referer = map( referer, safe_decoder ); prestate = mkmultiset( map( (array(string))indices( prestate ), safe_decoder ) ); config = mkmultiset( map( (array(string))indices( config ), safe_decoder ) ); pragma = mkmultiset( map( (array(string))indices( pragma ), safe_decoder ) );
ed15161999-11-19Per Hedbor }
b1fca01996-11-12Per Hedbor // Parse a HTTP/1.1 HTTP/1.0 or 0.9 request, including form data and // state variables. Return 0 if more is expected, 1 if done, and -1 // if fatal error.
9a5c4c2002-07-03Per Hedbor Shuffler.Shuffle pipe; object throttler; // The inter-request throttling object.
ba88df1999-09-29Francesco Chemolli 
e5bad21998-02-10Per Hedbor private void setup_pipe()
b1fca01996-11-12Per Hedbor {
9a5c4c2002-07-03Per Hedbor  if(!my_fd) {
1842611997-05-30Henrik Grubbström (Grubba)  end(); return; }
86903b2003-01-23Martin Nilsson  pipe = core.get_shuffler( my_fd );
9a5c4c2002-07-03Per Hedbor  if( conf )
f9531d2004-04-04Martin Nilsson  conf->connection_add( this, pipe );
b1fca01996-11-12Per Hedbor }
199d031999-09-05Francesco Chemolli 
9a5c4c2002-07-03Per Hedbor void send(string|object what, int|void len, int|void start)
b1fca01996-11-12Per Hedbor { if(!what) return;
e5bad21998-02-10Per Hedbor  if(!pipe) setup_pipe();
9a5c4c2002-07-03Per Hedbor  if( len>0 && port_obj && port_obj->minimum_byterate ) call_out( end, len / port_obj->minimum_byterate ); pipe->add_source(what,start,len||strlen(what));
b1fca01996-11-12Per Hedbor }
5f6dae2000-08-13Per Hedbor void start_sender( )
9d8ea11999-04-16Henrik Grubbström (Grubba) { #ifdef FD_DEBUG
9a5c4c2002-07-03Per Hedbor  call_out(timer, 30, predef::time(1)); // Update FD with time...
9d8ea11999-04-16Henrik Grubbström (Grubba) #endif
9a5c4c2002-07-03Per Hedbor  if( throttler || conf->throttler ) pipe->set_throttler( throttler || conf->throttler ); pipe->set_done_callback( do_log ); pipe->start( );
7ed2732004-04-04Martin Nilsson  data_buffer = 0;
8bd18e2002-07-04Per Hedbor  pipe = 0;
9d8ea11999-04-16Henrik Grubbström (Grubba) }
b1fca01996-11-12Per Hedbor string scan_for_query( string f ) {
8a3aaf2001-12-05Henrik Grubbström (Grubba)  query=0; rest_query="";
b1fca01996-11-12Per Hedbor  if(sscanf(f,"%s?%s", f, query) == 2) { string v, a, b; foreach(query / "&", v) if(sscanf(v, "%s=%s", a, b) == 2) { a = http_decode_string(replace(a, "+", " ")); b = http_decode_string(replace(b, "+", " "));
2fdf092000-12-02Per Hedbor  real_variables[ a ] += ({ b });
b1fca01996-11-12Per Hedbor  } else if(strlen( rest_query )) rest_query += "&" + http_decode_string( v ); else rest_query = http_decode_string( v );
ebb1c51998-02-24Per Hedbor  rest_query=replace(rest_query, "+", "\000"); /* IDIOTIC STUPID STANDARD */
9211b21998-04-24Per Hedbor  }
b1fca01996-11-12Per Hedbor  return f; }
3e2c342001-01-11Per Hedbor #define OLD_RXML_CONFIG #ifdef OLD_RXML_CONFIG private void really_set_config(array mod_config)
b1fca01996-11-12Per Hedbor {
3e2c342001-01-11Per Hedbor  string url; if(sscanf(replace(raw_url,({"%3c","%3e","%3C","%3E" }), ({"<",">","<",">"})),"/<%*s>/%s",url)!=2) url = "/";
e3bda32000-01-12Martin Nilsson  else
3e2c342001-01-11Per Hedbor  url = "/"+url;
e3bda32000-01-12Martin Nilsson 
3e2c342001-01-11Per Hedbor  multiset do_mod_config( multiset config )
b1fca01996-11-12Per Hedbor  {
3e2c342001-01-11Per Hedbor  if(!mod_config) return config; foreach(mod_config, string m) if(m[0]=='-') config[m[1..]]=0; else config[m]=1; return config; };
0ddff61997-07-20Henrik Grubbström (Grubba) 
3e2c342001-01-11Per Hedbor  void do_send_reply( string what, string url ) {
36160e2004-05-24Stephen R. van den Berg  CHECK_FD_SAFE_USE;
fce66d2001-08-13Martin Stjernholm  url = url_base() + url[1..];
dcc8952001-10-09Marcus Wellhardh  my_fd->set_blocking();
86903b2003-01-23Martin Nilsson  my_fd->write( prot + " 302 ChiliMoon config coming up\r\n"+
da4bf62001-10-09Marcus Wellhardh  (what?what+"\r\n":"")+"Location: "+url+"\r\n"
3e2c342001-01-11Per Hedbor  "Connection: close\r\nDate: "+ Roxen.http_date(predef::time(1))+ "\r\nContent-Type: text/html\r\n"
dcc8952001-10-09Marcus Wellhardh  "Content-Length: 1\r\n\r\nx" );
3e2c342001-01-11Per Hedbor  my_fd->close(); my_fd = 0; end(); };
0ddff61997-07-20Henrik Grubbström (Grubba) 
3e2c342001-01-11Per Hedbor  if(supports->cookies) { do_send_reply("Set-Cookie: "+ Roxen.http_roxen_config_cookie(indices(do_mod_config(config))*","), url ); return;
b1fca01996-11-12Per Hedbor  }
3e2c342001-01-11Per Hedbor  if (sscanf(replace(url, ({ "%28", "%29" }), ({ "(", ")" })), "/(%*s)/%s", url) == 2) url = "/" + url; do_send_reply(0,Roxen.add_pre_state( url, do_mod_config( prestate ) ));
b1fca01996-11-12Per Hedbor }
a3ebea2000-08-12Per Hedbor #endif
b1fca01996-11-12Per Hedbor 
0a635b1998-03-08Henrik Grubbström (Grubba) private static mixed f, line;
b5218e1999-03-18Henrik Grubbström (Grubba) private static int hstart;
0a635b1998-03-08Henrik Grubbström (Grubba) 
55533a2002-03-22Ian Delahorne //! Parse a cookie string. //! //! @param contents //! HTTP transport-encoded cookie header value. //! //! @returns //! Returns the resulting current cookie mapping. mapping(string:string) parse_cookies( string contents ) { if(!contents) return cookies;
36160e2004-05-24Stephen R. van den Berg // misc->cookies += ({contents});
55533a2002-03-22Ian Delahorne  foreach(((contents/";") - ({""})), string c) { string name, value; while(sizeof(c) && c[0]==' ') c=c[1..]; if(sscanf(c, "%s=%s", name, value) == 2) { value=http_decode_string(value); name=http_decode_string(name); cookies[ name ]=value; #ifdef OLD_RXML_CONFIG if( (name == "RoxenConfig") && strlen(value) ) config = mkmultiset( value/"," ); #endif } } return cookies; }
dcc8952001-10-09Marcus Wellhardh int things_to_do_when_not_sending_from_cache( )
a86c3b2000-08-28Per Hedbor { #ifdef OLD_RXML_CONFIG array mod_config; int config_in_url; #endif
bf25432001-02-24Per Hedbor  array|string contents;
a86c3b2000-08-28Per Hedbor  misc->pref_languages=PrefLanguages();
a2a5aa2000-08-31Per Hedbor  misc->cachekey = CacheKey(); misc->_cachecallbacks = ({});
bf25432001-02-24Per Hedbor  if( contents = request_headers[ "accept-language" ] )
a86c3b2000-08-28Per Hedbor  {
bf25432001-02-24Per Hedbor  if( !arrayp( contents ) ) contents = (contents-" ")/",";
a86c3b2000-08-28Per Hedbor  else
bf25432001-02-24Per Hedbor  contents = Array.flatten( map( map( contents, `-, " " ), `/, "," ))-({""}); misc->pref_languages->languages=contents; misc["accept-language"] = contents;
a86c3b2000-08-28Per Hedbor  }
bf25432001-02-24Per Hedbor 
a86c3b2000-08-28Per Hedbor  if( contents = request_headers[ "cookie" ] ) {
55533a2002-03-22Ian Delahorne  // FIXME: // "misc->cookies"? Shouldn't it be just "cookies"? // /grubba 2002-03-22
bf25432001-02-24Per Hedbor  misc->cookies = ({}); foreach( arrayp( contents )? contents : ({ contents }), contents )
a86c3b2000-08-28Per Hedbor  {
55533a2002-03-22Ian Delahorne  parse_cookies(contents);
a86c3b2000-08-28Per Hedbor  } } string f = raw_url; f = scan_for_query( f ); f = http_decode_string( f );
4a9aaa2001-02-06Johan Schön  // f is sent to Unix API's that take NUL-terminated strings...
4c9bdc2002-07-05Martin Nilsson  if( has_value(f, "\0") )
4a9aaa2001-02-06Johan Schön  sscanf(f, "%s\0", f);
a86c3b2000-08-28Per Hedbor  if( strlen( f ) > 5 ) { string a; switch( f[1] ) { #ifdef OLD_RXML_CONFIG case '<': if (sscanf(f, "/<%s>/%s", a, f)==2) { config_in_url = 1; mod_config = (a/","); f = "/"+f; } #endif // intentional fall-through case '(':
273ac22000-08-28Per Hedbor  if(strlen(f) && sscanf(f, "/(%s)/%s", a, f)==2)
a86c3b2000-08-28Per Hedbor  { prestate = (multiset)( a/","-({""}) ); f = "/"+f; } } } not_query = Roxen.simplify_path(f); #ifndef DISABLE_SUPPORTS
f163772000-08-28Per Hedbor  if( !supports )
a86c3b2000-08-28Per Hedbor  { if( !client ) { client = ({ "unknown" }); array s_and_v = find_supports_and_vars("", supports); supports = s_and_v[0]; client_var = s_and_v[1]; } else { if( !client_var->Fullname ) client_var->Fullname = "unknown"; client_var->fullname=lower_case(client_var->Fullname); array s_and_v=find_supports_and_vars(client_var->fullname,supports,client_var); supports = s_and_v[0]; client_var = s_and_v[1]; } } if ( client_var->charset && client_var->charset != "iso-8859-1" ) {
7ed2732004-04-04Martin Nilsson  misc->no_proto_cache = 1;
a86c3b2000-08-28Per Hedbor  set_output_charset( client_var->charset ); input_charset = client_var->charset; decode_charset_encoding( client_var->charset ); } #else supports = (< "images", "gifinline", "forms", "mailto">); #endif
f136c22002-02-26Martin Stjernholm  //REQUEST_WERR("HTTP: parse_got(): supports");
a86c3b2000-08-28Per Hedbor  if(!referer) referer = ({ }); if(misc->proxyauth) { // The Proxy-authorization header should be removed... So there. mixed tmp1,tmp2; foreach(tmp2 = (raw / "\n"), tmp1) {
98ac722002-10-02Martin Nilsson  if(has_prefix(lower_case(tmp1), "proxy-authorization:"))
a86c3b2000-08-28Per Hedbor  tmp2 -= ({tmp1}); } raw = tmp2 * "\n"; } #ifdef OLD_RXML_CONFIG if(config_in_url) {
f136c22002-02-26Martin Stjernholm  //REQUEST_WERR("HTTP: parse_got(): config_in_url");
e056e92000-10-19Per Hedbor  really_set_config( mod_config );
dcc8952001-10-09Marcus Wellhardh  return 1;
a86c3b2000-08-28Per Hedbor  } #endif if(!supports->cookies) config = prestate; else
bc0fa02001-03-08Per Hedbor  if( port_obj->set_cookie
cf03072004-05-23Stephen R. van den Berg  && !cookies->ChiliMoonUserID && strlen(not_query)
a86c3b2000-08-28Per Hedbor  && not_query[0]=='/' && method!="PUT") { if (!(port_obj->set_cookie_only_once && cache_lookup("hosts_for_cookie",remoteaddr))) misc->moreheads = ([ "Set-Cookie":Roxen.http_roxen_id_cookie(), ]); if (port_obj->set_cookie_only_once) cache_set("hosts_for_cookie",remoteaddr,1); }
2fdf092000-12-02Per Hedbor  if( mixed q = real_variables->magic_roxen_automatic_charset_variable )
f9531d2004-04-04Martin Nilsson  decode_charset_encoding(Roxen.get_client_charset_decoder(q[0], this));
2fdf092000-12-02Per Hedbor }
d25fde2000-10-17Per Hedbor 
a3ebea2000-08-12Per Hedbor static Roxen.HeaderParser hp = Roxen.HeaderParser();
d25fde2000-10-17Per Hedbor static function(string:array(string|mapping)) hpf = hp->feed;
8fb48a2000-06-26David Hedbor int last;
d25fde2000-10-17Per Hedbor 
a3ebea2000-08-12Per Hedbor private int parse_got( string new_data )
b1fca01996-11-12Per Hedbor {
9c19002001-02-27Per Hedbor  TIMER_START(parse_got);
a3ebea2000-08-12Per Hedbor  if( !method ) { array res;
8988e72004-04-04Martin Nilsson  if( mixed err = catch( res = hpf( new_data ) ) ) { #ifdef DEBUG report_debug("Got bad request, HeaderParser error: " + describe_error(err)); #endif
26b0b92001-10-02Per Hedbor  return 1;
8988e72004-04-04Martin Nilsson  }
a3ebea2000-08-12Per Hedbor  if( !res )
9c19002001-02-27Per Hedbor  { TIMER_END(parse_got);
26b0b92001-10-02Per Hedbor  return 0; // Not enough data
9c19002001-02-27Per Hedbor  }
a3ebea2000-08-12Per Hedbor  data = res[0]; line = res[1];
d25fde2000-10-17Per Hedbor  request_headers = res[2];
a3ebea2000-08-12Per Hedbor  }
36160e2004-05-24Stephen R. van den Berg  TIMER_END(parse_got);
26b0b92001-10-02Per Hedbor  return parse_got_2(); }
a3ebea2000-08-12Per Hedbor 
26b0b92001-10-02Per Hedbor private final int parse_got_2( ) {
36160e2004-05-24Stephen R. van den Berg  TIMER_START(parse_got_2); TIMER_START(parse_got_2_parse_line);
26b0b92001-10-02Per Hedbor  string trailer, trailer_trailer; multiset (string) sup; string a, b, s="", linename, contents;
94add02001-02-01Henrik Grubbström (Grubba)  array(string) sl = line / " ";
c0202a2001-02-01Per Hedbor  switch( sizeof( sl ) )
a3ebea2000-08-12Per Hedbor  {
c0202a2001-02-01Per Hedbor  default:
94add02001-02-01Henrik Grubbström (Grubba)  sl = ({ sl[0], sl[1..sizeof(sl)-2]*" ", sl[-1] }); /* FALL_THROUGH */
c0202a2001-02-01Per Hedbor  case 3: /* HTTP/1.0 */ method = sl[0]; f = sl[1]; clientprot = sl[2]; prot = clientprot; if(!(< "HTTP/1.0", "HTTP/1.1" >)[prot]) {
1100ac2001-06-25Martin Nilsson  int maj,min; if( sscanf(prot, "HTTP/%d.%d", maj, min) == 2 ) // Comply with the annoying weirdness of RFC 2616. prot = "HTTP/" + maj + "." + min; else // We're nice here and assume HTTP even if the protocol // is something very weird. prot = "HTTP/1.1";
c0202a2001-02-01Per Hedbor  } break; case 2: // HTTP/0.9 case 1: // PING method = sl[0]; f = sl[-1]; if( sizeof( sl ) == 1 ) sscanf( method, "%s%*[\r\n]", method ); clientprot = prot = "HTTP/0.9"; if(method != "PING") method = "GET"; // 0.9 only supports get. else { my_fd->write("PONG\r\n");
36160e2004-05-24Stephen R. van den Berg  TIMER_END(parse_got_2);
c0202a2001-02-01Per Hedbor  return 2; } s = data = ""; // no headers or extra data... sscanf( f, "%s%*[\r\n]", f );
7ed2732004-04-04Martin Nilsson  misc->no_proto_cache = 1;
c0202a2001-02-01Per Hedbor  break;
94add02001-02-01Henrik Grubbström (Grubba)  case 0: /* Not reached */ break;
c4ab8f1999-07-15David Hedbor  }
36160e2004-05-24Stephen R. van den Berg  TIMER_END(parse_got_2_parse_line);
f136c22002-02-26Martin Stjernholm  REQUEST_WERR(sprintf("HTTP: request line %O", line)); REQUEST_WERR(sprintf("HTTP: headers %O", request_headers)); REQUEST_WERR(sprintf("HTTP: data (length %d) %O", strlen(data),data));
b1fca01996-11-12Per Hedbor  raw_url = f;
e2df6a2001-01-03Per Hedbor  time = predef::time(1);
7970471999-07-15Henrik Grubbström (Grubba)  // if(!data) data = "";
f136c22002-02-26Martin Stjernholm  //REQUEST_WERR(sprintf("HTTP: raw_url %O", raw_url));
7ec6601997-01-29Per Hedbor 
b1fca01996-11-12Per Hedbor  if(!remoteaddr) {
41b77c1999-07-15David Hedbor  if(my_fd) { remoteaddr = my_fd->query_address();
abdff21999-12-27Martin Nilsson  if(remoteaddr)
41b77c1999-07-15David Hedbor  sscanf(remoteaddr, "%s %*s", remoteaddr); }
e5bad21998-02-10Per Hedbor  if(!remoteaddr) {
f136c22002-02-26Martin Stjernholm  REQUEST_WERR("HTTP: No remote address.");
36160e2004-05-24Stephen R. van den Berg  TIMER_END(parse_got_2);
41b77c1999-07-15David Hedbor  return 2;
e5bad21998-02-10Per Hedbor  }
b1fca01996-11-12Per Hedbor  }
7ec6601997-01-29Per Hedbor 
36160e2004-05-24Stephen R. van den Berg  TIMER_START(parse_got_2_parse_headers);
d25fde2000-10-17Per Hedbor  foreach( (array)request_headers, [string linename, array|string contents] )
e8b2142001-05-08Per Hedbor  { if( arrayp(contents) ) contents = contents[0];
d25fde2000-10-17Per Hedbor  switch (linename)
b1fca01996-11-12Per Hedbor  {
7357bd2002-01-16Henrik Grubbström (Grubba)  case "cache-control": // Opera sends "no-cache" here.
d25fde2000-10-17Per Hedbor  case "pragma": pragma|=(multiset)((contents-" ")/","); break;
7357bd2002-01-16Henrik Grubbström (Grubba) 
d25fde2000-10-17Per Hedbor  case "content-length": misc->len = (int)contents; break; case "authorization": rawauth = contents; break;
e8b2142001-05-08Per Hedbor  case "referer": referer = ({contents}); break;
d25fde2000-10-17Per Hedbor  case "if-modified-since": since=contents; break;
36160e2004-05-24Stephen R. van den Berg  case "if-match": break; // Not supported yet. case "if-none-match": none_match = (multiset)((contents-" ")/","); break;
d25fde2000-10-17Per Hedbor  case "proxy-authorization": array y; y = contents / " "; if(sizeof(y) < 2)
a86c3b2000-08-28Per Hedbor  break;
d25fde2000-10-17Per Hedbor  y[1] = decode(y[1]); misc->proxyauth=y; break;
a3ebea2000-08-12Per Hedbor 
d25fde2000-10-17Per Hedbor  case "user-agent": if( !client ) { sscanf(contents, "%s via", contents); client_var->Fullname=contents; client = contents/" " - ({ "" }); } break;
a3ebea2000-08-12Per Hedbor 
d25fde2000-10-17Per Hedbor  case "request-range": contents = lower_case(contents-" ");
98ac722002-10-02Martin Nilsson  if(has_prefix(contents, "bytes"))
d25fde2000-10-17Per Hedbor  // Only care about "byte" ranges. misc->range = contents[6..]; break;
a3ebea2000-08-12Per Hedbor 
d25fde2000-10-17Per Hedbor  case "range": contents = lower_case(contents-" ");
98ac722002-10-02Martin Nilsson  if(!misc->range && has_prefix(contents, "bytes"))
d25fde2000-10-17Per Hedbor  // Only care about "byte" ranges. Also the Request-Range header // has precedence since Stupid Netscape (TM) sends both but can't // handle multipart/byteranges but only multipart/x-byteranges. // Duh!!! misc->range = contents[6..]; break;
a3ebea2000-08-12Per Hedbor 
d25fde2000-10-17Per Hedbor  case "connection":
36160e2004-05-24Stephen R. van den Berg  misc->client_connection = (<@(lower_case(contents)/" " - ({""}))>); if (misc->client_connection->close) { misc->connection = "close"; } else if (misc->client_connection["keep-alive"]) { misc->connection = "keep-alive"; } break; case "host":
d25fde2000-10-17Per Hedbor  misc[linename] = lower_case(contents); break;
ff07142002-03-27Anders Johansson  case "content-type": misc[linename] = contents; break;
36160e2004-05-24Stephen R. van den Berg  case "destination": if (mixed err = catch {
01ee532004-05-27Stephen R. van den Berg  contents = http_decode_string (Standards.URI(contents)->path);
36160e2004-05-24Stephen R. van den Berg  }) { #ifdef DEBUG
01ee532004-05-27Stephen R. van den Berg  report_debug("Destination header contained a bad URI: %O\n" "%s", contents, describe_error(err));
36160e2004-05-24Stephen R. van den Berg #endif /* DEBUG */ }
01ee532004-05-27Stephen R. van den Berg  misc["new-uri"] = VFS.normalize_path (contents);
36160e2004-05-24Stephen R. van den Berg  break;
41b77c1999-07-15David Hedbor  }
51dd022001-05-08Anders Johansson  }
36160e2004-05-24Stephen R. van den Berg  TIMER_END(parse_got_2_parse_headers); TIMER_START(parse_got_2_more_data);
faf7c02001-08-23Henrik Grubbström (Grubba)  if(misc->len)
a86c3b2000-08-28Per Hedbor  { if(!data) data=""; int l = misc->len; wanted_data=l; have_data=strlen(data);
fdd26d2000-07-23Stefan Wallström 
a86c3b2000-08-28Per Hedbor  if(strlen(data) < l) {
f136c22002-02-26Martin Stjernholm  REQUEST_WERR(sprintf("HTTP: More data needed in %s.", method));
36160e2004-05-24Stephen R. van den Berg  ready_to_receive(); TIMER_END(parse_got_2);
a86c3b2000-08-28Per Hedbor  return 0; } leftovers = data[l+2..]; data = data[..l+1];
fdd26d2000-07-23Stefan Wallström 
36160e2004-05-24Stephen R. van den Berg  switch(method) { case "POST":
faf7c02001-08-23Henrik Grubbström (Grubba)  switch(lower_case((((misc["content-type"]||"")+";")/";")[0]-" ")) { default: // Normal form data. string v; // Ok.. This might seem somewhat odd, but IE seems to add a // (spurious) \r\n to the end of the data, and some versions of
01f8b82001-11-05Henrik Grubbström (Grubba)  // opera seem to add (spurious) \r\n to the start of the data.
faf7c02001-08-23Henrik Grubbström (Grubba)  // // Oh, the joy of supporting all webbrowsers is endless. data = String.trim_all_whites( data ); l = misc->len = strlen(data); if(l < 200000) foreach(replace(data,"+"," ")/"&", v) if(sscanf(v, "%s=%s", a, b) == 2) { a = http_decode_string( a ); b = http_decode_string( b ); real_variables[ a ] += ({ b }); } break;
a86c3b2000-08-28Per Hedbor 
faf7c02001-08-23Henrik Grubbström (Grubba)  case "multipart/form-data":
d0739e2002-02-14Henrik Grubbström (Grubba)  object messg = MIME.Message(data, request_headers); if (!messg->body_parts) { report_error("HTTP: Bad multipart/form-data.\n" " headers:\n" "%{ %O:%O\n%}" " data:\n" "%{ %O\"\\n\"\n%}", (array)request_headers, data/"\n"); /* FIXME: Should this be reported to the client? */ } else { foreach(messg->body_parts, object part)
faf7c02001-08-23Henrik Grubbström (Grubba)  {
d0739e2002-02-14Henrik Grubbström (Grubba)  if(part->disp_params->filename) { real_variables[part->disp_params->name] += ({part->getdata()}); real_variables[part->disp_params->name+".filename"] += ({part->disp_params->filename}); misc->files += ({ part->disp_params->name }); } else real_variables[part->disp_params->name] += ({part->getdata()});
2a42a32002-04-19Stefan Wallström  if(part->headers["content-type"]) real_variables[part->disp_params->name+".mimetype"] += ({ part->headers["content-type"] });
d0739e2002-02-14Henrik Grubbström (Grubba)  }
5118342004-05-21Stephen R. van den Berg  stash_body_parts = real_variables + ([ ]);
faf7c02001-08-23Henrik Grubbström (Grubba)  } break; }
dde9651996-12-08David Hedbor  }
ceb9271997-05-15David Hedbor  }
36160e2004-05-24Stephen R. van den Berg  TIMER_END(parse_got_2_more_data);
8e7d8c2001-11-07Henrik Grubbström (Grubba)  if (!(< "HTTP/1.0", "HTTP/0.9" >)[prot]) {
01f8b82001-11-05Henrik Grubbström (Grubba)  if (!misc->host) { // RFC 2616 requires this behaviour. REQUEST_WERR("HTTP: HTTP/1.1 request without a host header."); my_fd->write((prot||"HTTP/1.1") + " 400 Bad request (missing host header).\r\n" "Content-Length: 0\r\n" "Date: "+Roxen.http_date(predef::time())+"\r\n" "\r\n");
36160e2004-05-24Stephen R. van den Berg  TIMER_END(parse_got_2);
01f8b82001-11-05Henrik Grubbström (Grubba)  return 2; } }
36160e2004-05-24Stephen R. van den Berg  TIMER_END(parse_got_2);
41b77c1999-07-15David Hedbor  return 3; // Done.
b1fca01996-11-12Per Hedbor }
2fdf092000-12-02Per Hedbor int get_max_cache() { return misc->cacheable; } int set_max_cache( int t ) { int ot = misc->cacheable; misc->cacheable = t; return ot; }
a86c3b2000-08-28Per Hedbor 
b1fca01996-11-12Per Hedbor void disconnect() {
ebb1c51998-02-24Per Hedbor  file = 0;
f9531d2004-04-04Martin Nilsson  conf && conf->connection_drop( this );
36160e2004-05-24Stephen R. van den Berg  if (my_fd) {
f136c22002-02-26Martin Stjernholm  MARK_FD("HTTP my_fd in HTTP disconnected?");
36160e2004-05-24Stephen R. van den Berg  my_fd->close(); my_fd = 0; }
9c19002001-02-27Per Hedbor  MERGE_TIMERS(conf); if(do_not_disconnect) return;
14179b1997-01-29Per Hedbor  destruct();
b1fca01996-11-12Per Hedbor }
36160e2004-05-24Stephen R. van den Berg static void cleanup_request_object()
b1fca01996-11-12Per Hedbor {
01f4392002-03-28Per Hedbor  if( conf )
f9531d2004-04-04Martin Nilsson  conf->connection_drop( this );
36160e2004-05-24Stephen R. van den Berg } void end(int|void keepit) { CHECK_FD_SAFE_USE; cleanup_request_object();
0aee222000-08-15Martin Stjernholm  if(keepit
c60a402000-08-22Per Hedbor  && !file->raw
36160e2004-05-24Stephen R. van den Berg  && misc->connection != "close" && ((prot == "HTTP/1.1") || (misc->connection == "keep-alive"))
01f4392002-03-28Per Hedbor  && my_fd
36160e2004-05-24Stephen R. van den Berg  // Is this necessary now when this function no longer is called // from the close callback? /mast
01f4392002-03-28Per Hedbor  && !catch(my_fd->query_address()) )
ebb1c51998-02-24Per Hedbor  { // Now.. Transfer control to a new http-object. Reset all variables etc..
c659612004-05-24Martin Nilsson  this_program o = this_program(0, 0, 0);
ebb1c51998-02-24Per Hedbor  o->remoteaddr = remoteaddr;
be16102000-08-16Per Hedbor  o->client = client;
ebb1c51998-02-24Per Hedbor  o->supports = supports;
5f6dae2000-08-13Per Hedbor  o->client_var = client_var;
ebb1c51998-02-24Per Hedbor  o->host = host;
26f44e2000-08-13Per Hedbor  o->conf = conf;
5f6dae2000-08-13Per Hedbor  o->pipe = pipe;
36160e2004-05-24Stephen R. van den Berg  o->connection_misc = connection_misc; o->kept_alive = kept_alive+1;
0aee222000-08-15Martin Stjernholm  object fd = my_fd; my_fd=0; o->chain(fd,port_obj,leftovers);
5f6dae2000-08-13Per Hedbor  pipe = 0;
0aee222000-08-15Martin Stjernholm  disconnect();
ebb1c51998-02-24Per Hedbor  return; }
36160e2004-05-24Stephen R. van den Berg  data_buffer = 0;
5f6dae2000-08-13Per Hedbor  pipe = 0;
0aee222000-08-15Martin Stjernholm  disconnect();
b1fca01996-11-12Per Hedbor }
9211b21998-04-24Per Hedbor static void do_timeout()
b1fca01996-11-12Per Hedbor {
e2df6a2001-01-03Per Hedbor  int elapsed = predef::time(1)-time;
9211b21998-04-24Per Hedbor  if(time && elapsed >= 30)
8afc811998-02-04Per Hedbor  {
4fbdeb2002-07-17Martin Nilsson  REQUEST_WERR("HTTP: Connection timed out. Closing.");
3235691998-03-26Per Hedbor  MARK_FD("HTTP timeout");
5f6dae2000-08-13Per Hedbor  end();
8afc811998-02-04Per Hedbor  } else {
36160e2004-05-24Stephen R. van den Berg #ifdef DEBUG error ("This shouldn't happen.\n"); #endif
ebb1c51998-02-24Per Hedbor  // premature call_out... *¤#!"
8afc811998-02-04Per Hedbor  call_out(do_timeout, 10);
3235691998-03-26Per Hedbor  MARK_FD("HTTP premature timeout");
8afc811998-02-04Per Hedbor  }
b1fca01996-11-12Per Hedbor }
8641d42000-03-24Martin Stjernholm string link_to(string file, int line, string fun, int eid, int qq)
86e77d1998-05-07Per Hedbor {
8641d42000-03-24Martin Stjernholm  if (!file || !line) return "<a>"; if(file[0]!='/') file = combine_path(getcwd(), file);
4f6d922000-03-27Johan Sundström  return ("<a href=\"/(old_error,find_file)/error/?"+
3befe12000-08-22Martin Stjernholm  "file="+Roxen.http_encode_url(file)+ (fun ? "&fun="+Roxen.http_encode_url(fun) : "") +
8641d42000-03-24Martin Stjernholm  "&off="+qq+ "&error="+eid+
36160e2004-05-24Stephen R. van den Berg  "&error_md5="+get_err_md5(get_err_info(eid))+
8641d42000-03-24Martin Stjernholm  (line ? "&line="+line+"#here" : "") + "\">");
86e77d1998-05-07Per Hedbor }
8641d42000-03-24Martin Stjernholm static string error_page_header (string title) {
7dba2f2000-05-08Martin Nilsson  title = Roxen.html_encode_string (title);
8641d42000-03-24Martin Stjernholm  return #"<html><head><title>" + title + #"</title></head> <body bgcolor='white' text='black' link='#ce5c00' vlink='#ce5c00'> <table width='100%'><tr>
387ba92004-05-27Stephen R. van den Berg <td><a href='http://www.roxen.com/'><img border='0' src='/%01/roxen-small'></a></td>
8641d42000-03-24Martin Stjernholm <td><b><font size='+1'>" + title + #"</font></b></td>
0576d52002-10-22Martin Nilsson <td align='right'><font size='+1'>ChiliMoon " + Roxen.html_encode_string (roxen_version()) + #"</font></td>
8641d42000-03-24Martin Stjernholm </tr></table> "; }
86e77d1998-05-07Per Hedbor 
36160e2004-05-24Stephen R. van den Berg static string get_err_md5(array(string|array(string)|array(array)) err_info)
2b9d4b1998-03-25Per Hedbor {
36160e2004-05-24Stephen R. van den Berg  if (err_info) { return String.string2hex(Crypto.MD5.hash(err_info[3])); } return "NONE"; }
06be652002-07-04Martin Nilsson 
36160e2004-05-24Stephen R. van den Berg static array(string|array(string)|array(array)) get_err_info(int eid, string|void md5) { array(string|array(string)|array(array)) err_info = core.query_var ("errors")[eid]; if (!err_info || (md5 && (md5 != get_err_md5(err_info)))) { // Extra safety... return 0; } return err_info; } string format_backtrace(int eid, string|void md5) { array(string|array(string)|array(array)) err_info = get_err_info(eid, md5); if (!err_info) { return error_page_header("Unregistred Error"); } [string msg, array(string) rxml_bt, array(array) bt, string raw_bt_descr, string raw_url, string raw] = err_info;
8641d42000-03-24Martin Stjernholm  string res = error_page_header ("Internal Server Error") +
7dba2f2000-05-08Martin Nilsson  "<h1>" + replace (Roxen.html_encode_string (msg), "\n", "<br />\n") + "</h1>\n";
8641d42000-03-24Martin Stjernholm  if (rxml_bt && sizeof (rxml_bt)) { res += "<h3>RXML frame backtrace</h3>\n<ul>\n"; foreach (rxml_bt, string line)
7dba2f2000-05-08Martin Nilsson  res += "<li>" + Roxen.html_encode_string (line) + "</li>\n";
8641d42000-03-24Martin Stjernholm  res += "</ul>\n\n"; }
c658b92000-03-24Martin Stjernholm  if (bt && sizeof (bt)) {
8641d42000-03-24Martin Stjernholm  res += "<h3>Pike backtrace</h3>\n<ul>\n"; int q = sizeof (bt);
664da62001-06-08Martin Stjernholm  foreach(bt, [string file, int line, string func, string descr])
0efa772001-09-05Marcus Comstedt  { #if constant(PIKE_MODULE_RELOC) file = file && master()->relocate_module(file); #endif
8641d42000-03-24Martin Stjernholm  res += "<li value="+(q--)+">" + link_to (file, line, func, eid, q) +
7dba2f2000-05-08Martin Nilsson  (file ? Roxen.html_encode_string (file) : "<i>Unknown program</i>") +
8641d42000-03-24Martin Stjernholm  (line ? ":" + line : "") +
3d77732001-12-04Martin Stjernholm  "</a>" + (file ? Roxen.html_encode_string (get_cvs_id (file)) : "") + ":<br />\n" +
7dba2f2000-05-08Martin Nilsson  replace (Roxen.html_encode_string (descr),
3befe12000-08-22Martin Stjernholm  ({"(", ")", " "}), ({"<b>(</b>", "<b>)</b>", "&nbsp;"})) +
8641d42000-03-24Martin Stjernholm  "</li>\n";
0efa772001-09-05Marcus Comstedt  }
8641d42000-03-24Martin Stjernholm  res += "</ul>\n\n";
2b9d4b1998-03-25Per Hedbor  }
8641d42000-03-24Martin Stjernholm 
36160e2004-05-24Stephen R. van den Berg  res += ("<p><b><a href=\"/(old_error,plain)/error/?" "error="+eid+ "&error_md5="+get_err_md5(get_err_info(eid))+ "\">"
8641d42000-03-24Martin Stjernholm  "Generate text only version of this error message, for bug reports"+ "</a></b></p>\n\n");
258bb12000-03-15Martin Nilsson  return res+"</body></html>";
2b9d4b1998-03-25Per Hedbor }
b1fca01996-11-12Per Hedbor 
8641d42000-03-24Martin Stjernholm string generate_bugreport(string msg, array(string) rxml_bt, array(string) bt,
2827392000-03-26Martin Stjernholm  string raw_bt_descr, string raw_url, string raw)
2b9d4b1998-03-25Per Hedbor {
86903b2003-01-23Martin Nilsson  return ("ChiliMoon version: "+version()+ (core.real_version != version()? " ("+core.real_version+")":"")+
2827392000-03-26Martin Stjernholm  "\nPike version: " + predef::version() + "\nRequested URL: "+raw_url+"\n" "\nError: " + raw_bt_descr + "\nRequest data:\n"+raw);
f288181998-05-25Per Hedbor } string censor(string what) { string a, b, c;
0322b71999-08-06Per Hedbor  if(!what) return "No backtrace";
8641d42000-03-24Martin Stjernholm  if(sscanf(what, "%suthorization:%s\n%s", a, b, c)==3) return a+"uthorization: ################ (censored)\n"+c;
f288181998-05-25Per Hedbor  return what;
2b9d4b1998-03-25Per Hedbor }
b1fca01996-11-12Per Hedbor 
1d31342000-09-03Per Hedbor int store_error(mixed _err)
86e77d1998-05-07Per Hedbor {
1d31342000-09-03Per Hedbor  mixed err = _err; _err = 0; // hide in backtrace, they are bad enough anyway...
36160e2004-05-24Stephen R. van den Berg  mapping e = core.query_var("errors"); if(!e) core.set_var("errors", ([])); e = core.query_var("errors"); /* threads... */
abdff21999-12-27Martin Nilsson 
36160e2004-05-24Stephen R. van den Berg  int id = ++e[0]; if(id>1024) id = 1;
8641d42000-03-24Martin Stjernholm  string msg; array(string) rxml_bt; if (!err) msg = "Unknown error"; else { msg = describe_error (err); // Ugly, but it's hard to fix it better.. int i = search (msg, "\nRXML frame backtrace:\n"); if (i >= 0) { rxml_bt = (msg[i + sizeof ("\nRXML frame backtrace:")..] / "\n | ")[1..]; if (sizeof (rxml_bt)) rxml_bt[-1] = rxml_bt[-1][..sizeof (rxml_bt[-1]) - 2]; msg = msg[..i - 1]; } }
1d31342000-09-03Per Hedbor  function dp = master()->describe_program;
008c692001-03-16Martin Nilsson 
8641d42000-03-24Martin Stjernholm  string cwd = getcwd() + "/"; array bt;
c658b92000-03-24Martin Stjernholm  if (arrayp (err) && sizeof (err) >= 2 && arrayp (err[1]) || objectp (err) && err->is_generic_error) {
008c692001-03-16Martin Nilsson  object d = master()->Describer();
664da62001-06-08Martin Stjernholm  d->identify_parts(err[1]);
008c692001-03-16Martin Nilsson  function dcl = d->describe_comma_list;
8641d42000-03-24Martin Stjernholm  bt = ({});
008c692001-03-16Martin Nilsson 
664da62001-06-08Martin Stjernholm  foreach (reverse (err[1]), mixed ent) {
8641d42000-03-24Martin Stjernholm  string file, func, descr; int line; if (arrayp (ent)) { if (sizeof (ent) && stringp (ent[0])) if (ent[0][..sizeof (cwd) - 1] == cwd) file = ent[0] = ent[0][sizeof (cwd)..]; else file = ent[0]; if (sizeof (ent) >= 2) line = ent[1]; if (sizeof (ent) >= 3) if(functionp(ent[2])) {
3befe12000-08-22Martin Stjernholm  func = ""; if (object o = function_object (ent[2])) { string s; if (!catch (s = sprintf ("%O",o)) && s != "object") func = s + "->"; } func += function_name(ent[2]);
8641d42000-03-24Martin Stjernholm  if (!file) catch {
1d31342000-09-03Per Hedbor  file = dp(object_program( function_object( ent[2] ) ) );
8641d42000-03-24Martin Stjernholm  if (file[..sizeof (cwd) - 1] == cwd) file = file[sizeof (cwd)..]; }; } else if (stringp(ent[2])) func = ent[2];
2c639f2000-09-02Per Hedbor  else func ="<unknown function>";
8641d42000-03-24Martin Stjernholm  if (sizeof (ent) >= 4)
1d31342000-09-03Per Hedbor  descr = func + "(" +dcl(ent[3..],999999)+")";
8641d42000-03-24Martin Stjernholm  else descr = func + "()"; } else if (stringp (ent)) descr = ent; else if (catch (descr = sprintf ("%O", ent))) descr = "???"; bt += ({({file, line, func, descr})}); } }
3d77732001-12-04Martin Stjernholm  add_cvs_ids (err);
36160e2004-05-24Stephen R. van den Berg  e[id] = ({msg,rxml_bt,bt,describe_backtrace (err),raw_url,censor(raw)});
86e77d1998-05-07Per Hedbor  return id; }
36160e2004-05-24Stephen R. van den Berg array get_error(string eid, string md5)
86e77d1998-05-07Per Hedbor {
36160e2004-05-24Stephen R. van den Berg  mapping e = core.query_var("errors"); if(e) { array r = e[(int)eid]; if (r && md5 == String.string2hex(Crypto.MD5.hash(r[3]))) { return r; } } return 0;
86e77d1998-05-07Per Hedbor }
1d31342000-09-03Per Hedbor void internal_error(array _err)
b1fca01996-11-12Per Hedbor {
7ed2732004-04-04Martin Nilsson  misc->no_proto_cache = 1;
1d31342000-09-03Per Hedbor  mixed err = _err; _err = 0; // hide in backtrace, they are bad enough anyway...
bd22231998-03-27David Hedbor  array err2;
e9d1172001-07-31Per Hedbor  if(port_obj && port_obj->query("show_internals"))
86e77d1998-05-07Per Hedbor  {
abdff21999-12-27Martin Nilsson  err2 = catch {
7dba2f2000-05-08Martin Nilsson  file = Roxen.http_low_answer(500, format_backtrace(store_error(err)));
a7ebda2000-01-30Per Hedbor  };
bd22231998-03-27David Hedbor  if(err2) { werror("Internal server error in internal_error():\n" +
86e77d1998-05-07Per Hedbor  describe_backtrace(err2)+"\n while processing \n"+
bd22231998-03-27David Hedbor  describe_backtrace(err));
7dba2f2000-05-08Martin Nilsson  file = Roxen.http_low_answer(500, "<h1>Error: The server failed to "
bd22231998-03-27David Hedbor  "fulfill your query, due to an "
86e77d1998-05-07Per Hedbor  "internal error in the internal error routine.</h1>");
2b9d4b1998-03-25Per Hedbor  }
f788481998-03-18Henrik Grubbström (Grubba)  } else {
7dba2f2000-05-08Martin Nilsson  file = Roxen.http_low_answer(500, "<h1>Error: The server failed to "
2b9d4b1998-03-25Per Hedbor  "fulfill your query, due to an internal error.</h1>");
f788481998-03-18Henrik Grubbström (Grubba)  }
b1fca01996-11-12Per Hedbor  report_error("Internal server error: " + describe_backtrace(err) + "\n");
59f65b2000-01-05Henrik Grubbström (Grubba) #ifdef INTERNAL_ERROR_DEBUG
98501d2002-07-03Martin Nilsson  report_error("Raw backtrace:%O\n", err);
59f65b2000-01-05Henrik Grubbström (Grubba) #endif /* INTERNAL_ERROR_DEBUG */
b1fca01996-11-12Per Hedbor }
2b40f41999-12-29Martin Stjernholm // This macro ensures that something gets reported even when the very
36160e2004-05-24Stephen R. van den Berg // call to internal_error() fails. That happens eg when "this" has been
f9531d2004-04-04Martin Nilsson // destructed.
8988e72004-04-04Martin Nilsson #define INTERNAL_ERROR(err) do { \
36160e2004-05-24Stephen R. van den Berg  if (mixed __eRr = catch (internal_error (err))) \ report_error("Internal server error: " + describe_backtrace(err) + \ "internal_error() also failed: " + describe_backtrace(__eRr)); \ } while (0)
2b40f41999-12-29Martin Stjernholm 
23a7891996-12-15Per Hedbor int wants_more() { return !!cache; }
9a5c4c2002-07-03Per Hedbor void do_log( Shuffler.Shuffle r, int reason )
d7b0871997-08-31Per Hedbor {
3235691998-03-26Per Hedbor  MARK_FD("HTTP logging"); // fd can be closed here
9a5c4c2002-07-03Per Hedbor  int fsent = r->sent_data();
9c19002001-02-27Per Hedbor  TIMER_START(do_log);
d7b0871997-08-31Per Hedbor  if(conf) {
9a5c4c2002-07-03Per Hedbor  conf->sent+=fsent; file->len += misc->_log_cheat_addition;
f9531d2004-04-04Martin Nilsson  conf->log(file, this);
d7b0871997-08-31Per Hedbor  }
9a5c4c2002-07-03Per Hedbor 
35233d2000-09-01Per Hedbor  if( !port_obj ) {
9c19002001-02-27Per Hedbor  TIMER_END(do_log); MERGE_TIMERS(conf);
b611c62002-03-27Per Hedbor  if( conf )
f9531d2004-04-04Martin Nilsson  conf->connection_drop( this );
36160e2004-05-24Stephen R. van den Berg  call_out (disconnect, 0);
35233d2000-09-01Per Hedbor  return; }
9c19002001-02-27Per Hedbor  TIMER_END(do_log);
c60a402000-08-22Per Hedbor  end(1);
e5bad21998-02-10Per Hedbor  return;
d7b0871997-08-31Per Hedbor }
fa44bd1998-03-28David Hedbor #ifdef FD_DEBUG
4949d71998-03-28David Hedbor void timer(int start) {
aa92c11998-08-20Henrik Grubbström (Grubba)  if(pipe) { // FIXME: Disconnect if no data has been sent for a long while // (30min?)
f136c22002-02-26Martin Stjernholm  MARK_FD(sprintf("HTTP piping %d %d %d %d (%s)",
2c499e1998-03-28David Hedbor  pipe->sent, stringp(pipe->current_input) ?
b529001998-03-28David Hedbor  strlen(pipe->current_input) : -1,
9feab41998-03-28David Hedbor  pipe->last_called,
e2df6a2001-01-03Per Hedbor  predef::time(1) - start,
42ba931998-03-28David Hedbor  not_query));
aa92c11998-08-20Henrik Grubbström (Grubba)  } else {
42ba931998-03-28David Hedbor  MARK_FD("HTTP piping, but no pipe for "+not_query);
aa92c11998-08-20Henrik Grubbström (Grubba)  }
4949d71998-03-28David Hedbor  call_out(timer, 30, start); }
fa44bd1998-03-28David Hedbor #endif
86e77d1998-05-07Per Hedbor 
8641d42000-03-24Martin Stjernholm string handle_error_file_request (string msg, array(string) rxml_bt, array(array) bt,
2827392000-03-26Martin Stjernholm  string raw_bt_descr, string raw_url, string raw)
86e77d1998-05-07Per Hedbor { string data = Stdio.read_bytes(variables->file);
8641d42000-03-24Martin Stjernholm  if(!data) return error_page_header (variables->file) + "<h3><i>Source file could not be read</i></h3>\n" "</body></html>";
86e77d1998-05-07Per Hedbor  string down;
8641d42000-03-24Martin Stjernholm  int next = (int) variables->off + 1;
86e77d1998-05-07Per Hedbor 
8641d42000-03-24Martin Stjernholm  if(next < sizeof (bt)) { [string file, int line, string func, string descr] = bt[next]; down = link_to (file, line, func, (int) variables->error, next); }
86e77d1998-05-07Per Hedbor  else down = "<a>";
8641d42000-03-24Martin Stjernholm  int off = 49; array (string) lines = data/"\n"; int start = (int)variables->line-50; if(start < 0)
86e77d1998-05-07Per Hedbor  {
8641d42000-03-24Martin Stjernholm  off += start; start = 0; } int end = (int)variables->line+50;
86e77d1998-05-07Per Hedbor 
7dba2f2000-05-08Martin Nilsson  lines = map (lines[start..end], Roxen.html_encode_string);
8641d42000-03-24Martin Stjernholm  if(sizeof(lines)>off) { sscanf (lines[off], "%[ \t]%s", string indent, string code); if (!sizeof (code)) code = "&nbsp;"; lines[off] = indent + "<font size='+1'><b>"+down+code+"</a></b></font></a>";
86e77d1998-05-07Per Hedbor  }
8641d42000-03-24Martin Stjernholm  lines[max(off-20,0)] = "<a name=here>"+lines[max(off-20,0)]+"</a>";
abdff21999-12-27Martin Nilsson 
8641d42000-03-24Martin Stjernholm  return error_page_header (variables->file) + "<font size='-1'><pre>" + lines*"\n" + "</pre></font>\n" "</body></html>";
86e77d1998-05-07Per Hedbor }
d986281999-06-30David Hedbor // The wrapper for multiple ranges (send a multipart/byteranges reply).
34cf472003-01-14Peter Bortas #define BOUND "Byte_Me_Now_Chily"
d986281999-06-30David Hedbor  class MultiRangeWrapper { object file; function rcb; int current_pos, len, separator; array ranges; array range_info = ({}); string type; string stored_data = "";
84ae131999-07-28David Hedbor  void create(mapping _file, mapping heads, array _ranges, object id)
d986281999-06-30David Hedbor  { file = _file->file; len = _file->len; foreach(indices(heads), string h) { if(lower_case(h) == "content-type") { type = heads[h]; m_delete(heads, h); } }
84ae131999-07-28David Hedbor  if(id->request_headers["request-range"]) heads["Content-Type"] = "multipart/x-byteranges; boundary=" BOUND; else heads["Content-Type"] = "multipart/byteranges; boundary=" BOUND;
d986281999-06-30David Hedbor  ranges = _ranges; int clen; foreach(ranges, array range) { int rlen = 1+ range[1] - range[0];
84ae131999-07-28David Hedbor  string sep = sprintf("\r\n--" BOUND "\r\nContent-Type: %s\r\n"
d986281999-06-30David Hedbor  "Content-Range: bytes %d-%d/%d\r\n\r\n",
84ae131999-07-28David Hedbor  type||"application/octet-stream", @range, len);
d986281999-06-30David Hedbor  clen += rlen + strlen(sep); range_info += ({ ({ rlen, sep }) }); } clen += strlen(BOUND) + 8; // End boundary length. _file->len = clen; } string read(int num_bytes) { string out = stored_data; int rlen, total = num_bytes; num_bytes -= strlen(out);
037f4b1999-07-04David Hedbor  stored_data = "";
d986281999-06-30David Hedbor  foreach(ranges, array range) { rlen = range_info[0][0] - current_pos; if(separator != 1) { // New range, write new separator.
4ee9601999-07-02David Hedbor  // write("Initiating new range %d -> %d.\n", @range);
d986281999-06-30David Hedbor  out += range_info[0][1]; num_bytes -= strlen(range_info[0][1]); file->seek(range[0]); separator = 1; } if(num_bytes > 0) { if(rlen <= num_bytes) // Entire range fits. { out += file->read(rlen); num_bytes -= rlen; current_pos = separator = 0; ranges = ranges[1..]; // One range done. range_info = range_info[1..]; } else { out += file->read(num_bytes); current_pos += num_bytes; num_bytes = 0; } }
30f0321999-07-04David Hedbor  if(num_bytes <= 0) break; // Return data
d986281999-06-30David Hedbor  }
037f4b1999-07-04David Hedbor  if(!sizeof(ranges) && separator != 2) { // End boundary. Only write once and only when // no more ranges remain.
d986281999-06-30David Hedbor  separator = 2; out += "\r\n--" BOUND "--\r\n";
abdff21999-12-27Martin Nilsson  }
d986281999-06-30David Hedbor  if(strlen(out) > total) { // Oops. too much data again. Write and store. Write and store. stored_data = out[total..]; return out[..total-1]; } return out ; // We are finally done. }
abdff21999-12-27Martin Nilsson 
bceeba1999-07-05Henrik Grubbström (Grubba)  mixed `->(string what) {
d986281999-06-30David Hedbor  switch(what) { case "read": return read; case "set_nonblocking": return 0;
30f0321999-07-04David Hedbor  case "query_fd":
bceeba1999-07-05Henrik Grubbström (Grubba)  return lambda() { return -1; };
abdff21999-12-27Martin Nilsson 
d986281999-06-30David Hedbor  default: return file[what]; } } }
9c19002001-02-27Per Hedbor // Parse the range header into multiple ranges.
d986281999-06-30David Hedbor array parse_range_header(int len) { array ranges = ({}); foreach(misc->range / ",", string range) { int r1, r2; if(range[0] == '-' ) { // End of file request r1 = (len - (int)range[1..]); if(r1 < 0) {
abdff21999-12-27Martin Nilsson  // Entire file requested here.
d986281999-06-30David Hedbor  r1 = 0; }
abdff21999-12-27Martin Nilsson  ranges += ({ ({ len - (int)range[1..], len-1 }) });
d986281999-06-30David Hedbor  } else if(range[-1] == '-') { // Rest of file request r1 = (int)range; if(r1 >= len) // Range beginning is after EOF.
abdff21999-12-27Martin Nilsson  continue;
d986281999-06-30David Hedbor  ranges += ({ ({ r1, len-1 }) }); } else if(sscanf(range, "%d-%d", r1, r2)==2) { // Standard range if(r1 <= r2) { if(r1 >= len) // Range beginning is after EOF. continue; ranges += ({ ({ r1, r2 < len ? r2 : len -1 }) }); }
abdff21999-12-27Martin Nilsson  else
d986281999-06-30David Hedbor  // A syntatically incorrect range should make the server // ignore the header. Really. return 0; } else // Invalid syntax again...
abdff21999-12-27Martin Nilsson  return 0;
d986281999-06-30David Hedbor  } return ranges; }
45b22b1998-10-26Henrik Grubbström (Grubba) // Tell the client that it can start sending some more data void ready_to_receive() {
36160e2004-05-24Stephen R. van den Berg  // FIXME: Only send once? if (clientprot == "HTTP/1.1" && request_headers->expect && (request_headers->expect == "100-continue" || has_value(request_headers->expect, "100-continue" )))
45b22b1998-10-26Henrik Grubbström (Grubba)  my_fd->write("HTTP/1.1 100 Continue\r\n"); }
aa92c11998-08-20Henrik Grubbström (Grubba) 
d943c81998-05-18Henrik Grubbström (Grubba) // Send the result. void send_result(mapping|void result)
b1fca01996-11-12Per Hedbor {
9c19002001-02-27Per Hedbor  TIMER_START(send_result);
36160e2004-05-24Stephen R. van den Berg  CHECK_FD_SAFE_USE;
d943c81998-05-18Henrik Grubbström (Grubba)  array err;
5bc1991997-01-29Per Hedbor  int tmp;
5f6dae2000-08-13Per Hedbor  string head_string="";
26f44e2000-08-13Per Hedbor  if (result)
d943c81998-05-18Henrik Grubbström (Grubba)  file = result;
0d0e952000-11-13Per Hedbor #ifdef PROFILE
36160e2004-05-24Stephen R. van den Berg  int elapsed = HRTIME()-req_time;
0d0e952000-11-13Per Hedbor  string nid = #ifdef FILE_PROFILE (raw_url/"?")[0] #else dirname((raw_url/"?")[0]) #endif
36160e2004-05-24Stephen R. van den Berg  + "?method="+method;
0d0e952000-11-13Per Hedbor  array p;
36160e2004-05-24Stephen R. van den Berg  if(!(p=conf->profile_map[nid])) { // ({ count, sum, max }) p = conf->profile_map[nid] = ({0, 0, 0}); }
0d0e952000-11-13Per Hedbor  p[0]++; p[1] += elapsed; if(elapsed > p[2]) p[2]=elapsed; #endif
36160e2004-05-24Stephen R. van den Berg #ifdef DEBUG_CACHEABLE report_debug("<=== Request for %s returned cacheable %d (proto cache %s).\n", raw_url, misc->cacheable, misc->no_proto_cache ? "disabled" : "enabled"); #endif
7ed2732004-04-04Martin Nilsson  if( prot == "HTTP/0.9" ) misc->no_proto_cache = 1;
abdff21999-12-27Martin Nilsson 
36160e2004-05-24Stephen R. van den Berg  if(!leftovers)
5f6dae2000-08-13Per Hedbor  leftovers = data||"";
99b98b2000-08-14Per Hedbor  if(!mappingp(file))
b1fca01996-11-12Per Hedbor  {
7ed2732004-04-04Martin Nilsson  misc->no_proto_cache = 1;
99b98b2000-08-14Per Hedbor  if(misc->error_code)
36160e2004-05-24Stephen R. van den Berg  file = Roxen.http_status(misc->error_code, errors[misc->error]);
99b98b2000-08-14Per Hedbor  else if(err = catch {
f9531d2004-04-04Martin Nilsson  file = conf->error_file( this );
99b98b2000-08-14Per Hedbor  })
2b40f41999-12-29Martin Stjernholm  INTERNAL_ERROR(err);
99b98b2000-08-14Per Hedbor  }
36160e2004-05-24Stephen R. van den Berg  else { if((file->file == -1) || file->leave_me)
b1fca01996-11-12Per Hedbor  {
36160e2004-05-24Stephen R. van den Berg  TIMER_END(send_result); file = 0; pipe = 0; if(do_not_disconnect) return; my_fd = 0; return;
5f6dae2000-08-13Per Hedbor  }
abdff21999-12-27Martin Nilsson 
36160e2004-05-24Stephen R. van den Berg  if(file->type == "raw") file->raw = 1; } if(!file->raw && (prot != "HTTP/0.9")) { if (!sizeof (file) && multi_status) file = multi_status->http_answer(); if (file->error == Protocols.HTTP.HTTP_NO_CONTENT) { #if 0 // We actually give some content cf comment below. file->len = 2; file->data = "\r\n"; #else file->len = 0; file->data = ""; #endif /* 0 */
a60e412001-10-25Henrik Grubbström (Grubba)  }
edaa6f2001-02-01Per Hedbor 
36160e2004-05-24Stephen R. van den Berg  string head_status = file->rettext; if (head_status) { if (!file->file && !file->data && (!file->type || file->type == "text/html")) { // If we got no body then put the message there to make it // more visible. file->data = "<html><body>" + replace (Roxen.html_encode_string (head_status), "\n", "<br />\n") + "</body></html>"; file->len = sizeof (file->data); file->type = "text/html";
a8677c2002-10-24Martin Nilsson  }
36160e2004-05-24Stephen R. van den Berg  if (has_value (head_status, "\n")) // Fold lines nicely. head_status = map (head_status / "\n", String.trim_all_whites) * " ";
a8677c2002-10-24Martin Nilsson  }
edaa6f2001-02-01Per Hedbor 
36160e2004-05-24Stephen R. van den Berg  mapping(string:string) heads = make_response_headers (file); if (file->error == 200) { int conditional; if (none_match) { // NOTE: misc->etag may be zero below, but that's ok. if (none_match[misc->etag] || (misc->etag && none_match["*"])) { // We have a if-none-match header that matches our etag. if ((<"HEAD", "GET">)[method]) { // RFC 2616 14.26: // Instead, if the request method was GET or HEAD, the server // SHOULD respond with a 304 (Not Modified) response, including // the cache- related header fields (particularly ETag) of one // of the entities that matched. For all other request methods, // the server MUST respond with a status of 412 (Precondition // Failed). conditional = 304; } else { conditional = 412; } } else { conditional = -1; } } if(since && misc->last_modified && (conditional >= 0))
a8677c2002-10-24Martin Nilsson  {
36160e2004-05-24Stephen R. van den Berg  /* ({ time, len }) */ array(int) since_info = Roxen.parse_since( since ); // werror("since: %{%O, %}\n" // "lm: %O\n" // "cacheable: %O\n", // since_info, // misc->last_modified, // misc->cacheable); if ( ((since_info[0] >= misc->last_modified) && ((since_info[1] == -1) || (since_info[1] == file->len))) // never say 'not modified' if cacheable has been lowered. && (zero_type(misc->cacheable) || (misc->cacheable >= INITIAL_CACHEABLE)) // actually ok, or... // || ((misc->cacheable>0) // && (since_info[0] + misc->cacheable<= predef::time(1)) // // cacheable, and not enough time has passed. ) { conditional = conditional || 304; } else { conditional = -1; }
edaa6f2001-02-01Per Hedbor  }
36160e2004-05-24Stephen R. van den Berg  if (conditional > 0) { // All conditionals apply. file->error = conditional; file->file = file->data = file->len = 0; } else if(misc->range && file->len && objectp(file->file) && !file->data && (method == "GET" || method == "HEAD"))
5f6dae2000-08-13Per Hedbor  // Plain and simple file and a Range header. Let's play. // Also we only bother with 200-requests. Anything else should be // nicely and completely ignored. Also this is only used for GET and // HEAD requests. { // split the range header. If no valid ranges are found, ignore it. // If one is found, send that range. If many are found we need to // use a wrapper and send a multi-part message. array ranges = parse_range_header(file->len); if(ranges) // No incorrect syntax... {
7ed2732004-04-04Martin Nilsson  misc->no_proto_cache = 1;
5f6dae2000-08-13Per Hedbor  if(sizeof(ranges)) // And we have valid ranges as well. { file->error = 206; // 206 Partial Content if(sizeof(ranges) == 1) { heads["Content-Range"] = sprintf("bytes %d-%d/%d", @ranges[0], file->len);
36160e2004-05-24Stephen R. van den Berg  file->file->seek(ranges[0][0]); if(ranges[0][1] == (file->len - 1) && GLOBVAR(RestoreConnLogFull)) // Log continuations (ie REST in FTP), 'range XXX-' // using the entire length of the file, not just the // "sent" part. Ie add the "start" byte location when logging misc->_log_cheat_addition = ranges[0][0];
5f6dae2000-08-13Per Hedbor  file->len = ranges[0][1] - ranges[0][0]+1; } else { // Multiple ranges. Multipart reply and stuff needed. // We do this by replacing the file object with a wrapper. // Nice and handy.
f9531d2004-04-04Martin Nilsson  file->file = MultiRangeWrapper(file, heads, ranges, this);
5f6dae2000-08-13Per Hedbor  } } else {
36160e2004-05-24Stephen R. van den Berg  // Got the header, but the specified ranges were out of bounds.
5f6dae2000-08-13Per Hedbor  // Reply with a 416 Requested Range not satisfiable. file->error = 416; heads["Content-Range"] = "*/"+file->len;
36160e2004-05-24Stephen R. van den Berg  if(method == "GET") { file->file = file->data = file->type = file->len = 0;
5f6dae2000-08-13Per Hedbor  } } }
36160e2004-05-24Stephen R. van den Berg  } }
6486122000-12-10Per Hedbor 
36160e2004-05-24Stephen R. van den Berg  head_string = sprintf("%s %d %s\r\n", prot, file->error, head_status || errors[file->error] || ""); // Must update the content length after the modifications of the // data to send that might have been done above for 206 or 304. heads["Content-Length"] = (string)file->len; // Some browsers, e.g. Netscape 4.7, don't trust a zero // content length when using keep-alive. So let's force a // close in that case. if( file->error/100 == 2 && file->len <= 0 ) { heads->Connection = "close"; misc->connection = "close"; }
6f32e32000-08-17Per Hedbor 
8988e72004-04-04Martin Nilsson  if( mixed err = catch( head_string += Roxen.make_http_headers( heads ) ) )
83d7582001-10-08Per Hedbor  {
8988e72004-04-04Martin Nilsson #ifdef DEBUG
36160e2004-05-24Stephen R. van den Berg  report_debug ("Roxen.make_http_headers failed: " + describe_error (err));
8988e72004-04-04Martin Nilsson #endif
36160e2004-05-24Stephen R. van den Berg  foreach(heads; string x; string|array(string) val) { if (stringp(val)) head_string += x+": "+val+"\r\n"; else if( arrayp( val ) ) foreach( val, string xx )
83d7582001-10-08Per Hedbor  head_string += x+": "+xx+"\r\n"; else if( catch {
36160e2004-05-24Stephen R. van den Berg  head_string += x+": "+(string)val+"\r\n";
83d7582001-10-08Per Hedbor  } ) error("Illegal value in headers array! " "Expected string or array(string)\n");
36160e2004-05-24Stephen R. van den Berg  }
83d7582001-10-08Per Hedbor  head_string += "\r\n"; }
6f32e32000-08-17Per Hedbor 
36160e2004-05-24Stephen R. van den Berg  if (sscanf (heads["Content-Type"], "; charset=%s", string charset) || String.width( head_string ) > 8 )
83d7582001-10-08Per Hedbor  head_string = output_encode( head_string, 0, charset )[1];
5f6dae2000-08-13Per Hedbor  conf->hsent += strlen(head_string);
41b77c1999-07-15David Hedbor  }
36160e2004-05-24Stephen R. van den Berg  else if(!file->type) file->type="text/plain"; #if 0 REQUEST_WERR(sprintf("HTTP: Sending result for prot:%O, method:%O, file:%O", prot, method, file)); #endif
5f6dae2000-08-13Per Hedbor  MARK_FD("HTTP handled");
36160e2004-05-24Stephen R. van den Berg  if( (method!="HEAD") && (file->error!=204) )
5f6dae2000-08-13Per Hedbor  // No data for these two...
f71a6b2000-01-22Martin Stjernholm  {
5f6dae2000-08-13Per Hedbor #ifdef RAM_CACHE
c0202a2001-02-01Per Hedbor  if( (misc->cacheable > 0) && (file->data || file->file) &&
56324e2002-10-23Martin Nilsson  (prot != "HTTP/0.9") && !misc->no_proto_cache)
5f6dae2000-08-13Per Hedbor  {
a32a612000-11-02Per Hedbor  if( file->len>0 && // known length. ((file->len + strlen( head_string )) <
a2a5aa2000-08-31Per Hedbor  conf->datacache->max_file_size) && misc->cachekey )
5f6dae2000-08-13Per Hedbor  {
e2df6a2001-01-03Per Hedbor  string data = "";
93f7992000-08-14Per Hedbor  if( file->file ) data += file->file->read(); if( file->data ) data += file->data;
773ac62001-03-20Martin Stjernholm  MY_TRACE_ENTER (sprintf ("Storing in ram cache, entry: %O", raw_url), 0);
36160e2004-05-24Stephen R. van den Berg  MY_TRACE_LEAVE ("");
773ac62001-03-20Martin Stjernholm  conf->datacache->set( raw_url, data,
99b98b2000-08-14Per Hedbor  ([
e2df6a2001-01-03Per Hedbor  // We have to handle the date header. "hs":head_string,
a2a5aa2000-08-31Per Hedbor  "key":misc->cachekey,
36160e2004-05-24Stephen R. van den Berg  "etag":misc->etag,
a2a5aa2000-08-31Per Hedbor  "callbacks":misc->_cachecallbacks,
99b98b2000-08-14Per Hedbor  "len":file->len,
8765672000-08-28Per Hedbor  // fix non-keep-alive when sending from cache
dc6fe12001-08-20Per Hedbor  "raw":file->raw,
99b98b2000-08-14Per Hedbor  "error":file->error,
0a900b2000-08-17Per Hedbor  "mtime":(file->stat && file->stat[ST_MTIME]), "rf":realfile,
99b98b2000-08-14Per Hedbor  ]),
5f6dae2000-08-13Per Hedbor  misc->cacheable );
9c19002001-02-27Per Hedbor  file = ([ "data":data, "raw":file->raw, "len":strlen(data) ]);
5f6dae2000-08-13Per Hedbor  } } #endif
36160e2004-05-24Stephen R. van den Berg  if(!kept_alive && (file->len > 0) && ((sizeof(head_string) + file->len) < (HTTP_BLOCKING_SIZE_THRESHOLD))) { // The first time we get a request, the output buffers will // be empty. We can thus just do a single blocking write() // if the data will fit in the output buffer (usually 4KB). int s; TIMER_END(send_result); TIMER_START(blocking_write); string data = head_string; if (file->data) data += file->data[..file->len-1]; if (file->file) data += file->file->read(file->len); #ifdef CONNECTION_DEBUG werror ("HTTP: Response =================================================\n" "%s\n", replace (sprintf ("%O", data), ({"\\r\\n", "\\n", "\\t"}), ({"\n", "\n", "\t"}))); #else REQUEST_WERR (sprintf ("HTTP: Send blocking %O", data)); #endif s = my_fd->write(data); TIMER_END(blocking_write); return; } if(strlen(head_string)) send(head_string); if(file->data && strlen(file->data)) send(file->data, file->len); if(file->file) send(file->file, file->len);
f71a6b2000-01-22Martin Stjernholm  }
5f6dae2000-08-13Per Hedbor  else
3582882000-03-24Per Hedbor  {
36160e2004-05-24Stephen R. van den Berg  if( strlen( head_string ) < (HTTP_BLOCKING_SIZE_THRESHOLD)) { #ifdef CONNECTION_DEBUG werror ("HTTP: Response =================================================\n" "%s\n", replace (sprintf ("%O", head_string), ({"\\r\\n", "\\n", "\\t"}), ({"\n", "\n", "\t"}))); #else REQUEST_WERR (sprintf ("HTTP: Send headers blocking %O", head_string)); #endif return; }
3582882000-03-24Per Hedbor  send(head_string);
5f6dae2000-08-13Per Hedbor  file->len = 1; // Keep those alive, please... }
9c19002001-02-27Per Hedbor  TIMER_END(send_result);
5f6dae2000-08-13Per Hedbor  start_sender();
14179b1997-01-29Per Hedbor }
d943c81998-05-18Henrik Grubbström (Grubba) // Execute the request void handle_request( ) {
6a409d1999-12-27Martin Nilsson  REQUEST_WERR("HTTP: handle_request()");
9c19002001-02-27Per Hedbor  TIMER_START(handle_request);
d943c81998-05-18Henrik Grubbström (Grubba) #ifdef MAGIC_ERROR if(prestate->old_error) {
36160e2004-05-24Stephen R. van den Berg  array err = get_error(variables->error, variables->error_md5 || "NONE");
6306e52002-07-03Martin Nilsson  if(err && arrayp(err))
d943c81998-05-18Henrik Grubbström (Grubba)  { if(prestate->plain) { file = ([
2827392000-03-26Martin Stjernholm  "type":"text/plain",
f288181998-05-25Per Hedbor  "data":generate_bugreport( @err ),
d943c81998-05-18Henrik Grubbström (Grubba)  ]);
9c19002001-02-27Per Hedbor  TIMER_END(handle_request);
8a80d41999-05-20Per Hedbor  send_result(); return;
d943c81998-05-18Henrik Grubbström (Grubba)  } else { if(prestate->find_file) {
f9531d2004-04-04Martin Nilsson  if (!core.configuration_authenticate(this, "View Settings"))
7dba2f2000-05-08Martin Nilsson  file = Roxen.http_auth_required("admin");
d943c81998-05-18Henrik Grubbström (Grubba)  else
8641d42000-03-24Martin Stjernholm  file = ([ "type":"text/html", "data":handle_error_file_request( @err ), ]);
9c19002001-02-27Per Hedbor  TIMER_END(handle_request);
8a80d41999-05-20Per Hedbor  send_result(); return;
d943c81998-05-18Henrik Grubbström (Grubba)  } } } } #endif /* MAGIC_ERROR */ MARK_FD("HTTP handling request");
35c2631999-02-16Per Hedbor  array e;
8988e72004-04-04Martin Nilsson  mapping result;
f9531d2004-04-04Martin Nilsson  if(e= catch(result = conf->handle_request( this )))
2b40f41999-12-29Martin Stjernholm  INTERNAL_ERROR( e );
8988e72004-04-04Martin Nilsson  else { if (result && result->pipe) // Could be destructed here already since handle_request might // have handed over us to another thread that finished quickly. return; file = result; }
36160e2004-05-24Stephen R. van den Berg  if( file && file->try_again_later ) { if( objectp( file->try_again_later ) ) ; else call_out( core.handle, file->try_again_later, handle_request ); return; }
8988e72004-04-04Martin Nilsson 
9c19002001-02-27Per Hedbor  TIMER_END(handle_request);
26f44e2000-08-13Per Hedbor  send_result();
d943c81998-05-18Henrik Grubbström (Grubba) }
5430602001-07-21Martin Stjernholm string url_base()
b421932002-01-29Martin Stjernholm // See the RequestID class for doc.
5430602001-07-21Martin Stjernholm {
69a1832002-10-02Martin Nilsson  // Note: Code duplication in server_core/prototypes.pike.
5430602001-07-21Martin Stjernholm  if (!cached_url_base) { // First look at the host header in the request.
3c49612001-07-21Martin Stjernholm  if (string tmp = misc->host) {
fce66d2001-08-13Martin Stjernholm  int scanres = sscanf (tmp, "%[^:]:%d", string host, int port); if (scanres < 2) // Some clients don't send the port in the host header. port = port_obj->port; if (port_obj->default_port == port)
5430602001-07-21Martin Stjernholm  // Remove redundant port number.
fce66d2001-08-13Martin Stjernholm  cached_url_base = port_obj->prot_name + "://" + host;
5430602001-07-21Martin Stjernholm  else
fce66d2001-08-13Martin Stjernholm  if (scanres < 2) cached_url_base = port_obj->prot_name + "://" + host + ":" + port; else cached_url_base = port_obj->prot_name + "://" + tmp;
5430602001-07-21Martin Stjernholm  }
3c49612001-07-21Martin Stjernholm  // Then use the port object.
5430602001-07-21Martin Stjernholm  else {
36160e2004-05-24Stephen R. van den Berg  string host = (port_obj->conf_data[conf] || (["hostname":"*"]))->hostname;
3c49612001-07-21Martin Stjernholm  if (host == "*") if (conf && sizeof (host = conf->get_url()) && sscanf (host, "%*s://%[^:/]", host) == 2) { // Use the hostname in the configuration url. } else // Fall back to the numeric ip. host = port_obj->ip; cached_url_base = port_obj->prot_name + "://" + host;
5430602001-07-21Martin Stjernholm  if (port_obj->port != port_obj->default_port) cached_url_base += ":" + port_obj->port; } if (string p = misc->site_prefix_path) cached_url_base += p; cached_url_base += "/"; } return cached_url_base; }
14179b1997-01-29Per Hedbor /* We got some data on a socket.
abdff21999-12-27Martin Nilsson  * =================================================
14179b1997-01-29Per Hedbor  */
ebb1c51998-02-24Per Hedbor int processed;
0d0e952000-11-13Per Hedbor // array ccd = ({});
14179b1997-01-29Per Hedbor void got_data(mixed fooid, string s) {
36160e2004-05-24Stephen R. van den Berg #ifdef CONNECTION_DEBUG werror ("HTTP: Request --------------------------------------------------\n" "%s\n", replace (sprintf ("%O", s), ({"\\r\\n", "\\n", "\\t"}), ({"\n", "\n", "\t"}))); #else
f136c22002-02-26Martin Stjernholm  REQUEST_WERR(sprintf("HTTP: Got %O", s));
36160e2004-05-24Stephen R. van den Berg #endif
d0739e2002-02-14Henrik Grubbström (Grubba) 
0d0e952000-11-13Per Hedbor  if(wanted_data)
d042a82000-08-31Per Hedbor  {
36160e2004-05-24Stephen R. van den Berg  // NOTE: No need to make a data buffer if it's a small request.
0d0e952000-11-13Per Hedbor  if(strlen(s) + have_data < wanted_data)
d042a82000-08-31Per Hedbor  {
7ed2732004-04-04Martin Nilsson  if(!data_buffer) { // The 16384 is some reasonable extra padding to // avoid having to realloc. data_buffer = String.Buffer(wanted_data + 16384); data_buffer->add(data); data = ""; } data_buffer->add(s);
0d0e952000-11-13Per Hedbor  have_data += strlen(s);
7ed2732004-04-04Martin Nilsson 
4fbdeb2002-07-17Martin Nilsson  // Reset timeout. remove_call_out(do_timeout); call_out(do_timeout, 90);
0d0e952000-11-13Per Hedbor  REQUEST_WERR("HTTP: We want more data."); return; }
7ed2732004-04-04Martin Nilsson  if(data_buffer) { data_buffer->add(s); data = (string)data_buffer; data_buffer = 0; } else data += s;
d042a82000-08-31Per Hedbor  }
acd34a2000-01-22Martin Stjernholm  if (mixed err = catch {
26b0b92001-10-02Per Hedbor  MARK_FD("HTTP got data"); raw += s;
0d0e952000-11-13Per Hedbor 
26b0b92001-10-02Per Hedbor  // The port has been closed, but old (probably keep-alive) // connections remain. Close those connections. if( !port_obj )
14179b1997-01-29Per Hedbor  {
b611c62002-03-27Per Hedbor  if( conf )
f9531d2004-04-04Martin Nilsson  conf->connection_drop( this );
36160e2004-05-24Stephen R. van den Berg  MARK_FD ("HTTP: Port closed."); call_out (disconnect, 0);
26b0b92001-10-02Per Hedbor  return; }
abdff21999-12-27Martin Nilsson 
26b0b92001-10-02Per Hedbor  switch( parse_got( s ) ) { case 0: REQUEST_WERR("HTTP: Request needs more data."); return;
26f44e2000-08-13Per Hedbor 
26b0b92001-10-02Per Hedbor  case 1:
f136c22002-02-26Martin Stjernholm  REQUEST_WERR("HTTP: Stupid Client Error.");
26b0b92001-10-02Per Hedbor  my_fd->write((prot||"HTTP/1.0")+" 500 Illegal request\r\n" "Content-Length: 0\r\n"+ "Date: "+Roxen.http_date(predef::time())+"\r\n" "\r\n"); end(); return; // Stupid request. case 2:
f136c22002-02-26Martin Stjernholm  REQUEST_WERR("HTTP: Done.");
26b0b92001-10-02Per Hedbor  end(); return; }
abdff21999-12-27Martin Nilsson 
36160e2004-05-24Stephen R. van den Berg #ifdef CONNECTION_DEBUG werror ("HTTP: Request received -----------------------------------------\n"); #endif if( method == "GET" || method == "HEAD" ) {
26b0b92001-10-02Per Hedbor  misc->cacheable = INITIAL_CACHEABLE; // FIXME: Make configurable.
36160e2004-05-24Stephen R. van den Berg #ifdef DEBUG_CACHEABLE report_debug("===> Request for %s initiated cacheable to %d.\n", raw_url, misc->cacheable); #endif }
abdff21999-12-27Martin Nilsson 
26b0b92001-10-02Per Hedbor  TIMER_START(find_conf); string path; if( !conf || !(path = port_obj->path ) || (sizeof( path ) && raw_url[..sizeof(path) - 1] != path) )
a2a5aa2000-08-31Per Hedbor 
26b0b92001-10-02Per Hedbor  { // FIXME: port_obj->name & port_obj->default_port are constant // consider caching them?
0b03222001-11-14Henrik Grubbström (Grubba)  // RFC 2068 5.1.2: // // To allow for transition to absoluteURIs in all requests in future // versions of HTTP, all HTTP/1.1 servers MUST accept the absoluteURI // form in requests, even though HTTP/1.1 clients will only generate // them in requests to proxies.
34cf472003-01-14Peter Bortas #ifdef RFC2068
0b03222001-11-14Henrik Grubbström (Grubba)  if (has_prefix(raw_url, port_obj->name+"://") &&
f9531d2004-04-04Martin Nilsson  (conf = port_obj->find_configuration_for_url(raw_url, this, 1))) {
0b03222001-11-14Henrik Grubbström (Grubba)  sscanf(raw_url[sizeof(port_obj->name+"://")..], "%[^/]%s", misc->host, raw_url);
34cf472003-01-14Peter Bortas  } else #endif {
0b03222001-11-14Henrik Grubbström (Grubba)  if (misc->host) { conf = port_obj->find_configuration_for_url(port_obj->name + "://" + misc->host +
98ac722002-10-02Martin Nilsson  (has_value(misc->host, ":")<0? "":(":"+port_obj->port)) +
f9531d2004-04-04Martin Nilsson  raw_url, this);
0b03222001-11-14Henrik Grubbström (Grubba)  } else { conf = port_obj->find_configuration_for_url(port_obj->name + "://*:" + port_obj->port +
f9531d2004-04-04Martin Nilsson  raw_url, this);
0b03222001-11-14Henrik Grubbström (Grubba)  } }
26b0b92001-10-02Per Hedbor  } else if( strlen(path) ) adjust_for_config_path( path );
0aee222000-08-15Martin Stjernholm 
26b0b92001-10-02Per Hedbor  TIMER_END(find_conf);
26f44e2000-08-13Per Hedbor 
26b0b92001-10-02Per Hedbor  if (rawauth)
c5e0961999-10-04Per Hedbor  {
26b0b92001-10-02Per Hedbor  /* Need to authenticate with the configuration */
7ed2732004-04-04Martin Nilsson  misc->no_proto_cache = 1;
26b0b92001-10-02Per Hedbor  array(string) y = rawauth / " "; realauth = 0; auth = 0; if (sizeof(y) >= 2) { y[1] = MIME.decode_base64(y[1]); realauth = y[1]; }
c5e0961999-10-04Per Hedbor  }
26b0b92001-10-02Per Hedbor  if( misc->proxyauth )
c5e0961999-10-04Per Hedbor  {
26b0b92001-10-02Per Hedbor  /* Need to authenticate with the configuration */
7ed2732004-04-04Martin Nilsson  misc->no_proto_cache = 1;
26b0b92001-10-02Per Hedbor  if (sizeof(misc->proxyauth) >= 2) { // misc->proxyauth[1] = MIME.decode_base64(misc->proxyauth[1]); if (conf->auth_module) misc->proxyauth
f9531d2004-04-04Martin Nilsson  = conf->auth_module->auth(misc->proxyauth, this);
26b0b92001-10-02Per Hedbor  }
c5e0961999-10-04Per Hedbor  }
9a5c4c2002-07-03Per Hedbor  if( conf ) {
f9531d2004-04-04Martin Nilsson  conf->connection_add( this, ([]) );
9a5c4c2002-07-03Per Hedbor  conf->received += strlen(raw); conf->requests++; }
36160e2004-05-24Stephen R. van den Berg  CHECK_FD_SAFE_USE;
26b0b92001-10-02Per Hedbor  my_fd->set_close_callback(0); my_fd->set_read_callback(0);
8988e72004-04-04Martin Nilsson  if (my_fd->set_accept_callback) my_fd->set_accept_callback(0);
26b0b92001-10-02Per Hedbor  processed=1;
5f6dae2000-08-13Per Hedbor 
26b0b92001-10-02Per Hedbor  remove_call_out(do_timeout);
5f6dae2000-08-13Per Hedbor #ifdef RAM_CACHE
26b0b92001-10-02Per Hedbor  TIMER_START(cache_lookup); array cv; if( prot != "HTTP/0.9" && misc->cacheable &&
8988e72004-04-04Martin Nilsson  !misc->no_proto_cache &&
26b0b92001-10-02Per Hedbor  !since && (cv = conf->datacache->get( raw_url )) )
99b98b2000-08-14Per Hedbor  {
26b0b92001-10-02Per Hedbor  MY_TRACE_ENTER (sprintf ("Found %O in ram cache - checking entry", raw_url), 0); if( !cv[1]->key ) {
773ac62001-03-20Martin Stjernholm  MY_TRACE_LEAVE ("Entry invalid due to zero key");
26b0b92001-10-02Per Hedbor  conf->datacache->expire_entry( raw_url );
c3c6322000-09-20Per Hedbor  }
26b0b92001-10-02Per Hedbor  else
0a900b2000-08-17Per Hedbor  {
26b0b92001-10-02Per Hedbor  int can_cache = 1; if(!leftovers) leftovers = data||""; string d = cv[ 0 ]; file = cv[1]; if( sizeof(file->callbacks) ) { if( mixed e = catch { foreach( file->callbacks, function f ) { MY_TRACE_ENTER (sprintf ("Checking with %s", master()->describe_function (f)), 0);
f9531d2004-04-04Martin Nilsson  if( !f(this, cv[1]->key ) )
26b0b92001-10-02Per Hedbor  { MY_TRACE_LEAVE ("Entry invalid according to callback"); MY_TRACE_LEAVE (""); can_cache = 0; break; } MY_TRACE_LEAVE (""); } } ) { INTERNAL_ERROR( e ); TIMER_END(cache_lookup); send_result(); return; } } if( !cv[1]->key ) { MY_TRACE_LEAVE ("Entry invalid due to zero key"); conf->datacache->expire_entry( raw_url ); can_cache = 0; } if( can_cache ) {
a2a5aa2000-08-31Per Hedbor #ifndef RAM_CACHE_ASUME_STATIC_CONTENT
26b0b92001-10-02Per Hedbor  Stat st; if( !file->rf || !file->mtime || ((st = file_stat( file->rf )) && st->mtime == file->mtime ))
a2a5aa2000-08-31Per Hedbor #endif
26b0b92001-10-02Per Hedbor  { string fix_date( string headers ) { string a, b; if( sscanf( headers, "%sDate: %*s\n%s", a, b ) == 3 ) return a+"Date: "+Roxen.http_date( predef::time(1) ) +"\r\n"+b; return headers; }; MY_TRACE_LEAVE ("Using entry from ram cache"); conf->hsent += strlen(file->hs); cache_status["protcache"] = 1;
36160e2004-05-24Stephen R. van den Berg  if( strlen( d ) < (HTTP_BLOCKING_SIZE_THRESHOLD) ) { TIMER_END(cache_lookup); } else { TIMER_END(cache_lookup); send( fix_date(file->hs)+d ); start_sender( ); }
26b0b92001-10-02Per Hedbor  return; }
773ac62001-03-20Martin Stjernholm #ifndef RAM_CACHE_ASUME_STATIC_CONTENT
26b0b92001-10-02Per Hedbor  else MY_TRACE_LEAVE ( sprintf ("Entry out of date (disk: %s, cache: mtime %d)", st ? "mtime " + st->mtime : "gone", file->mtime));
773ac62001-03-20Martin Stjernholm #endif
26b0b92001-10-02Per Hedbor  } else
7ed2732004-04-04Martin Nilsson  misc->no_proto_cache = 1; // Never cache in this case.
26b0b92001-10-02Per Hedbor  file = 0; }
99b98b2000-08-14Per Hedbor  }
26b0b92001-10-02Per Hedbor  TIMER_END(cache_lookup);
46d4cb2001-08-22Martin Stjernholm #endif // RAM_CACHE
26b0b92001-10-02Per Hedbor  TIMER_START(parse_request);
dcc8952001-10-09Marcus Wellhardh  if( things_to_do_when_not_sending_from_cache( ) ) return;
36160e2004-05-24Stephen R. van den Berg  REQUEST_WERR(sprintf("HTTP: cooked headers %O", request_headers)); REQUEST_WERR(sprintf("HTTP: cooked variables %O", real_variables)); REQUEST_WERR(sprintf("HTTP: cooked cookies %O", cookies));
26b0b92001-10-02Per Hedbor  TIMER_END(parse_request);
a86c3b2000-08-28Per Hedbor 
86903b2003-01-23Martin Nilsson  REQUEST_WERR("HTTP: Calling core.handle()."); core.handle(handle_request);
653d7d2000-02-14Per Hedbor  }) {
acd34a2000-01-22Martin Stjernholm  report_error("Internal server error: " + describe_backtrace(err));
bc0fa02001-03-08Per Hedbor  my_fd->set_blocking();
acd34a2000-01-22Martin Stjernholm  my_fd->close();
36160e2004-05-24Stephen R. van den Berg  my_fd = 0;
acd34a2000-01-22Martin Stjernholm  disconnect(); }
b1fca01996-11-12Per Hedbor }
abdff21999-12-27Martin Nilsson /* Get a somewhat identical copy of this object, used when doing
b1fca01996-11-12Per Hedbor  * 'simulated' requests. */
c659612004-05-24Martin Nilsson this_program clone_me()
b1fca01996-11-12Per Hedbor {
c659612004-05-24Martin Nilsson  this_program c=this_program(0, port_obj, conf);
cbe6c62000-03-18Martin Stjernholm #ifdef ID_OBJ_DEBUG
f9531d2004-04-04Martin Nilsson  werror ("clone %O -> %O\n", this, c);
cbe6c62000-03-18Martin Stjernholm #endif
b1fca01996-11-12Per Hedbor 
0e5b1a1999-10-10Per Hedbor  c->port_obj = port_obj;
b1fca01996-11-12Per Hedbor  c->conf = conf;
ae727d2001-07-16Martin Nilsson  c->root_id = root_id;
b1fca01996-11-12Per Hedbor  c->time = time;
f6d62d1997-03-26Per Hedbor  c->raw_url = raw_url;
99cb5e2001-02-05Per Hedbor  c->real_variables = copy_value( real_variables ); c->variables = FakedVariables( c->real_variables );
a2a5aa2000-08-31Per Hedbor  c->misc = copy_value( misc );
f9531d2004-04-04Martin Nilsson  c->misc->orig = this;
f6d62d1997-03-26Per Hedbor 
b1fca01996-11-12Per Hedbor  c->prestate = prestate; c->supports = supports;
f6d62d1997-03-26Per Hedbor  c->config = config;
dc5f172000-04-28Martin Nilsson  c->client_var = client_var;
f6d62d1997-03-26Per Hedbor 
b1fca01996-11-12Per Hedbor  c->remoteaddr = remoteaddr;
f6d62d1997-03-26Per Hedbor  c->host = host;
b1fca01996-11-12Per Hedbor  c->client = client;
f6d62d1997-03-26Per Hedbor  c->referer = referer; c->pragma = pragma; c->cookies = cookies;
36160e2004-05-24Stephen R. van den Berg  c->request_headers = request_headers + ([]);
f6d62d1997-03-26Per Hedbor  c->my_fd = 0; c->prot = prot;
1afe371997-06-12Henrik Grubbström (Grubba)  c->clientprot = clientprot;
f6d62d1997-03-26Per Hedbor  c->method = method;
abdff21999-12-27Martin Nilsson  // realfile virtfile // Should not be copied.
f6d62d1997-03-26Per Hedbor  c->rest_query = rest_query; c->raw = raw; c->query = query; c->not_query = not_query; c->data = data;
746c3b1998-09-16Peter J. Holzer  c->extra_extension = extra_extension;
b1fca01996-11-12Per Hedbor  c->auth = auth; c->realauth = realauth;
f6d62d1997-03-26Per Hedbor  c->rawauth = rawauth; c->since = since;
b1fca01996-11-12Per Hedbor  return c; } void clean() {
4b71f51998-03-25David Hedbor  if(!(my_fd && objectp(my_fd))) end();
e2df6a2001-01-03Per Hedbor  else if((predef::time(1) - time) > 4800)
3235691998-03-26Per Hedbor  end();
b1fca01996-11-12Per Hedbor }
a3ebea2000-08-12Per Hedbor static void create(object f, object c, object cc)
b1fca01996-11-12Per Hedbor {
14179b1997-01-29Per Hedbor  if(f) {
8988e72004-04-04Martin Nilsson  f->set_nonblocking(got_data, f->query_write_callback(), end);
14179b1997-01-29Per Hedbor  my_fd = f;
36160e2004-05-24Stephen R. van den Berg  CHECK_FD_SAFE_USE;
f136c22002-02-26Martin Stjernholm  MARK_FD("HTTP connection");
a3ebea2000-08-12Per Hedbor  if( c ) port_obj = c; if( cc ) conf = cc;
e2df6a2001-01-03Per Hedbor  time = predef::time(1);
491abc2000-08-17Per Hedbor  call_out(do_timeout, 90);
14179b1997-01-29Per Hedbor  }
f9531d2004-04-04Martin Nilsson  root_id = this;
b1fca01996-11-12Per Hedbor }
ceb9271997-05-15David Hedbor 
9a5c4c2002-07-03Per Hedbor void chain( object f, object c, string le )
ebb1c51998-02-24Per Hedbor { my_fd = f;
8988e72004-04-04Martin Nilsson  f->set_nonblocking(0, f->query_write_callback(), end);
870a9e1999-10-04Per Hedbor  port_obj = c;
5f6dae2000-08-13Per Hedbor  processed = 0;
0aee222000-08-15Martin Stjernholm  do_not_disconnect=-1; // Block destruction until we return.
f136c22002-02-26Martin Stjernholm  MARK_FD("HTTP kept alive");
8988e72004-04-04Martin Nilsson  time = predef::time();
5f6dae2000-08-13Per Hedbor 
36160e2004-05-24Stephen R. van den Berg  if ( le && strlen( le ) )
5f6dae2000-08-13Per Hedbor  got_data( 0,le );
a7ebda2000-01-30Per Hedbor  else {
18c62d1999-05-27Stephen R. van den Berg  // If no pipelined data is available, call out...
d391422000-03-25Martin Stjernholm  remove_call_out(do_timeout);
491abc2000-08-17Per Hedbor  call_out(do_timeout, 90);
18c62d1999-05-27Stephen R. van den Berg  }
4949d71998-03-28David Hedbor 
0aee222000-08-15Martin Stjernholm  if(!my_fd) { if(do_not_disconnect == -1) { do_not_disconnect=0; disconnect(); } } else
ebb1c51998-02-24Per Hedbor  {
0aee222000-08-15Martin Stjernholm  if(do_not_disconnect == -1) do_not_disconnect = 0;
36160e2004-05-24Stephen R. van den Berg  f->set_nonblocking(!processed && got_data, f->query_write_callback(), end);
ebb1c51998-02-24Per Hedbor  } }
08bd3c1999-11-02Per Hedbor 
86903b2003-01-23Martin Nilsson string _sprintf(int t)
08bd3c1999-11-02Per Hedbor {
86903b2003-01-23Martin Nilsson  if(t!='O') return 0;
33098a2002-04-05Henrik Grubbström (Grubba)  return "RequestID(" + (raw_url||"") + ")"
8bf31a2000-03-20Martin Stjernholm #ifdef ID_OBJ_DEBUG
33098a2002-04-05Henrik Grubbström (Grubba)  + (__marker ? "[" + __marker->count + "]" : "")
8bf31a2000-03-20Martin Stjernholm #endif
33098a2002-04-05Henrik Grubbström (Grubba)  ;
08bd3c1999-11-02Per Hedbor }
84fb682000-02-03Per Hedbor  Stdio.File connection( ) { return my_fd; } Configuration configuration() { return conf; }