2a2a5b1996-12-01Per Hedbor // This is a roxen module. (c) Informationsvävarna AB 1996.
ceb9271997-05-15David Hedbor string cvs_version = "$Id: http.pike,v 1.26 1997/05/15 23:30:45 neotron Exp $";
2a2a5b1996-12-01Per Hedbor // HTTP protocol module.
b1fca01996-11-12Per Hedbor #include <config.h>
fc2fcf1997-04-13Per Hedbor private inherit "roxenlib";
b1fca01996-11-12Per Hedbor int first;
14179b1997-01-29Per Hedbor constant shuffle=roxen->shuffle; constant decode=roxen->decode; constant find_supports=roxen->find_supports; constant version=roxen->version; constant handle=roxen->handle; constant _query=roxen->query; //constant This = object_program(this_object());
0829d51997-03-03Henrik Grubbström (Grubba) import Simulate;
b1fca01996-11-12Per Hedbor  function _time=time;
7ee5651996-12-10Per Hedbor private static array(string) cache; private static int wanted_data, have_data;
b1fca01996-11-12Per Hedbor object conf; #ifdef REQUEST_DEBUG int kept_alive; #endif #include <roxen.h> #include <module.h>
ceb9271997-05-15David Hedbor #undef SPEED_MAX
b1fca01996-11-12Per Hedbor  #undef QUERY
14179b1997-01-29Per Hedbor #define QUERY(X) _query("X")
b1fca01996-11-12Per Hedbor  int time; string raw_url; int do_not_disconnect = 0; mapping (string:string) variables = ([ ]); mapping (string:mixed) misc = ([ ]); multiset (string) prestate = (< >); multiset (string) config = (< >); multiset (string) supports = (< >); string remoteaddr, host; array (string) client = ({ "Unknown" }); array (string) referer = ({ }); multiset (string) pragma = (< >); mapping (string:string) cookies = ([ ]); mixed file; object my_fd; /* The client. */ object pipe; // string range; string prot; string method; string realfile, virtfile; string rest_query=""; string raw; string query; string not_query; string extra_extension = ""; // special hack for the language module string data; array (int|string) auth; string rawauth, realauth; string since;
ceb9271997-05-15David Hedbor  #if _DEBUG_HTTP_OBJECTS int my_id; int my_state; #endif
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. void end(string|void); private void setup_pipe(int noend) {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 6; #endif
b1fca01996-11-12Per Hedbor  if(!my_fd) return end();
5e89211997-02-13Per Hedbor  if(!pipe) pipe=Pipe.pipe();
48fa361997-04-05Per Hedbor // if(!noend) pipe->set_done_callback(end);
b1fca01996-11-12Per Hedbor #ifdef REQUEST_DEBUG perror("REQUEST: Pipe setup.\n"); #endif // pipe->output(my_fd); } void send(string|object what, int|void noend) {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 7; #endif
b1fca01996-11-12Per Hedbor  if(!what) return; if(!pipe) setup_pipe(noend); #ifdef REQUEST_DEBUG perror("REQUEST: Sending some data\n"); #endif if(stringp(what)) pipe->write(what); else pipe->input(what); } string scan_for_query( string f ) {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 8; #endif
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, "+", " ")); if(variables[ a ]) variables[ a ] += "\0" + b; else variables[ a ] = b; } else if(strlen( rest_query )) rest_query += "&" + http_decode_string( v ); else rest_query = http_decode_string( v ); } rest_query=replace(rest_query, "+", "\000"); /* IDIOTIC STUPID STANDARD */ return f; } private int really_set_config(array mod_config) { string url, m; string base;
14179b1997-01-29Per Hedbor  base = conf->query("MyWorldLocation")||"/";
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 8; #endif
b1fca01996-11-12Per Hedbor  if(supports->cookies) { #ifdef REQUEST_DEBUG perror("Setting cookie..\n"); #endif if(mod_config) foreach(mod_config, m) if(m[-1]=='-') config[m[1..]]=0; else config[m]=1; if(sscanf(replace(raw_url,({"%3c","%3e","%3C","%3E" }), ({"<",">","<",">"})),"/<%*s>/%s",url)!=2) url = "/"; url = base + url; my_fd->write(prot+" 302 Config in cookie!\r\n" "Set-Cookie: " +http_roxen_config_cookie(indices(config)*",")+"\r\n" "Location: "+url+"\r\n" "Content-Type: text/html\r\n" "Content-Length: 0\r\n\r\n"); } else { #ifdef REQUEST_DEBUG perror("Setting {config} for user without Cookie support..\n"); #endif if(mod_config) foreach(mod_config, m) if(m[-1]=='-') prestate[m[1..]]=0; else prestate[m]=1; sscanf(replace(raw_url, ({ "%3c", "%3e", "%3C", "%3E" }), ({ "<", ">", "<", ">" })), "/<%*s>/%s", url); sscanf(replace(url, ({ "%28", "%29" }), ({ "(", ")" })),"/(%*s)/%s", url); my_fd->write(prot+" 302 Config In Prestate!\r\n"
14179b1997-01-29Per Hedbor  +"\r\nLocation: "+conf->query("MyWorldLocation")+
3cecfe1997-04-26Per Hedbor  add_pre_state(url, prestate)+"\r\n"
b1fca01996-11-12Per Hedbor  +"Content-Type: text/html\r\n" +"Content-Length: 0\r\n\r\n"); } return -2; } private int parse_got(string s) {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 9; #endif
b1fca01996-11-12Per Hedbor  multiset (string) sup; array mod_config; mixed f, line; string a, b, linename, contents, real_raw; int config_in_url;
ceb9271997-05-15David Hedbor // roxen->httpobjects[my_id] = "Parsed data...";
b1fca01996-11-12Per Hedbor  real_raw = s; s -= "\r"; // I just hate all thoose CR LF. if(strlen(s) < 3) return 0; // Not finished, I promise. if(!(s[-1] == '\n' && search(s, "HTTP/") == -1)) if(search(s, "\n\n") == -1) return 0; raw = s; s = replace(s, "\t", " "); if(sscanf(s,"%s %s %s\n%s", method, f, prot, s) < 4) { if(sscanf(s,"%s %s\n", method, f) < 2) f=""; s=""; prot = "HTTP/0.9"; } if(!method) method = "GET"; method = upper_case(method); if(method == "PING") { my_fd->write("PONG\n"); return -2; } raw_url = f; time = _time(1);
b04f071997-01-29Per Hedbor 
7ec6601997-01-29Per Hedbor 
b1fca01996-11-12Per Hedbor  if(!remoteaddr) { catch(remoteaddr = ((my_fd->query_address()||"")/" ")[0]); if(!remoteaddr) this_object()->end(); }
7ec6601997-01-29Per Hedbor 
b1fca01996-11-12Per Hedbor #if 0 sscanf(f,"%s;%s", f, range); #endif f = scan_for_query( f ); f = http_decode_string( f ); if (sscanf(f, "/<%s>%s", a, f)) { config_in_url = 1; mod_config = (a/","); } if (sscanf(f, "/(%s)%s", a, f) && strlen(a)) prestate = aggregate_multiset(@(a/","-({""}))); not_query = f; if(strlen(s)) { sscanf(real_raw, "%s\r\n\r\n%s", s, data); /* We do _not_ want to parse the 'GET ...\n' line. /Per */ sscanf(s, "%*s\n%s", s); s = replace(s, "\n\t", ", ") - "\r"; // Handle rfc822 continuation lines and strip \r foreach(s/"\n" - ({ "" }), line) { linename=contents=0; sscanf(line, "%s:%s", linename, contents); if(linename&&contents) { linename=lower_case(linename); sscanf(contents, "%*[\t ]%s", contents); if(strlen(contents)) { switch (linename) {
7ee5651996-12-10Per Hedbor  case "content-length":
b1fca01996-11-12Per Hedbor  misc->len = (int)(contents-" "); if(method == "POST") { int l = (int)(contents-" ")-1; /* Length - 1 */
7ee5651996-12-10Per Hedbor  wanted_data=l; have_data=strlen(data);
ceb9271997-05-15David Hedbor  if(strlen(data) <= l) // \r are included. { #if _DEBUG_HTTP_OBJECTS roxen->httpobjects[my_id] = "Parsed data - short post..."; #endif
7ee5651996-12-10Per Hedbor  return 0;
ceb9271997-05-15David Hedbor  }
7ee5651996-12-10Per Hedbor  data = data[..l]; switch(lower_case(((misc["content-type"]||"")/";")[0]-" "))
ceb9271997-05-15David Hedbor  { default: // Normal form data.
7ee5651996-12-10Per Hedbor  string v; if(l < 200000) { foreach(replace(data-"\n", "+", " ")/"&", v) if(sscanf(v, "%s=%s", a, b) == 2) { a = http_decode_string( a ); b = http_decode_string( b );
b1fca01996-11-12Per Hedbor 
7ee5651996-12-10Per Hedbor  if(variables[ a ]) variables[ a ] += "\0" + b; else variables[ a ] = b; } } break; case "multipart/form-data": string boundary; // perror("Multipart/form-data post detected\n"); sscanf(misc["content-type"], "%*sboundary=%s",boundary); foreach((data/("--"+boundary))-({"--",""}), contents) { string pre, metainfo,post; if(sscanf(contents, "%[\r\n]%*[Cc]ontent-%*[dD]isposition:%[^\r\n]%[\r\n]%s", pre,metainfo,post,contents)>4) { mapping info=([]); if(!strlen(contents)) continue; while(contents[-1]=='-') contents=contents[..strlen(contents)-2]; if(contents[-1]=='\r')contents=contents[..strlen(contents)-2]; if(contents[-1]=='\n')contents=contents[..strlen(contents)-2]; if(contents[-1]=='\r')contents=contents[..strlen(contents)-2]; foreach(metainfo/";", v) { sscanf(v, "%*[ \t]%s", v); v=reverse(v); sscanf(v, "%*[ \t]%s", v); v=reverse(v); if(lower_case(v)!="form-data") { string var, value; if(sscanf(v, "%s=\"%s\"", var, value)) info[lower_case(var)]=value; } } if(info->filename) { variables[info->name]=contents; variables[info->name+".filename"]=info->filename;
92a5271996-12-10Per Hedbor  if(!misc->files) misc->files = ({ info->name }); else misc->files += ({ info->name });
7ee5651996-12-10Per Hedbor  } else { variables[info->name]=contents; } } } break; } } break;
b1fca01996-11-12Per Hedbor  case "authorization": string *y; rawauth = contents; y = contents /= " "; if(sizeof(y) < 2) break; y[1] = decode(y[1]); realauth=y[1]; if(conf && conf->auth_module) y = conf->auth_module->auth( y, this_object() ); auth=y; break; case "proxy-authorization": string *y; y = contents /= " "; if(sizeof(y) < 2) break; y[1] = decode(y[1]); if(conf && conf->auth_module) y = conf->auth_module->auth( y, this_object() ); misc->proxyauth=y; break; case "pragma":
5e89211997-02-13Per Hedbor  pragma|=aggregate_multiset(@replace(contents, " ", "")/ ",");
b1fca01996-11-12Per Hedbor  break; case "user-agent": sscanf(contents, "%s via", contents);
5e89211997-02-13Per Hedbor  client = contents/" " - ({ "" });
b1fca01996-11-12Per Hedbor  break;
695bba1997-03-22Henrik Grubbström (Grubba)  /* Some of M$'s non-standard user-agent info */ case "ua-pixels": /* Screen resolution */ case "ua-color": /* Color scheme */ case "ua-os": /* OS-name */ case "ua-cpu": /* CPU-type */ /* None of the above are interresting or usefull */ /* IGNORED */ break;
b1fca01996-11-12Per Hedbor  case "referer":
f6d62d1997-03-26Per Hedbor  referer = contents/" "; break;
b1fca01996-11-12Per Hedbor  case "extension": #ifdef DEBUG perror("Client extension: "+contents+"\n"); #endif linename="extension"; case "connection": contents = lower_case(contents); case "content-type": misc[linename] = lower_case(contents); break; case "accept": case "accept-encoding":
fc2fcf1997-04-13Per Hedbor  case "accept-charset":
b1fca01996-11-12Per Hedbor  case "accept-language": case "session-id": case "message-id": case "from": if(misc[linename])
5e89211997-02-13Per Hedbor  misc[linename] += (contents-" ") / ",";
b1fca01996-11-12Per Hedbor  else
5e89211997-02-13Per Hedbor  misc[linename] = (contents-" ") / ",";
b1fca01996-11-12Per Hedbor  break; case "cookie": /* This header is quite heavily parsed */ string c; misc->cookies = contents; foreach(contents/";", c) { string name, value; while(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; if(name == "RoxenConfig" && strlen(value)) { array tmpconfig = value/"," + ({ }); string m; if(mod_config && sizeof(mod_config)) foreach(mod_config, m) if(!strlen(m)) { continue; } /* Bug in parser force { and } */ else if(m[0]=='-') tmpconfig -= ({ m[1..] }); else tmpconfig |= ({ m }); mod_config = 0; config = aggregate_multiset(@tmpconfig); } } } break; case "host": case "proxy-connection": case "security-scheme": misc[linename] = contents; break; case "proxy-by": case "proxy-maintainer": case "proxy-software": #ifdef MORE_HEADERS if(misc[linename]) misc[linename] += explode(contents-" ", ","); else misc[linename] = explode(contents-" ", ","); #endif case "mime-version": break; case "if-modified-since":
14179b1997-01-29Per Hedbor // if(QUERY(IfModified))
b1fca01996-11-12Per Hedbor  since=contents; break; case "forwarded": misc["forwarded"]=contents; break; #ifdef DEBUG default: /* x-* headers are experimental. */ if(linename[0] != 'x') perror("Unknown header: `"+linename+"' -> `"+contents+"'\n"); #endif } } } } }
14179b1997-01-29Per Hedbor  supports = find_supports(lower_case(client*" "));
b1fca01996-11-12Per Hedbor 
dde9651996-12-08David Hedbor  if(misc->proxyauth) { // The Proxy-authorization header should be removed... So there. mixed tmp1,tmp2; foreach(tmp2 = (raw / "\n"), tmp1) { if(!search(lower_case(tmp1), "proxy-authorization:")) tmp2 -= ({tmp1}); } raw = tmp2 * "\n";
b1fca01996-11-12Per Hedbor  }
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 10; roxen->httpobjects[my_id] = sprintf("%O - %O", raw_url, remoteaddr); #endif if(config_in_url) { #if _DEBUG_HTTP_OBJECTS roxen->httpobjects[my_id] = "Configuration request?..."; #endif return really_set_config( mod_config ); }
b1fca01996-11-12Per Hedbor  if(!supports->cookies) config = prestate; else if(conf
27b0e11996-11-26Per Hedbor  && !cookies->RoxenUserID && strlen(not_query) && not_query[0]=='/' && method!="PUT" && QUERY(set_cookie))
b1fca01996-11-12Per Hedbor  { #ifdef DEBUG perror("Setting unique ID.\n"); #endif misc->moreheads = ([ "Set-Cookie":http_roxen_id_cookie(), ]); } #ifdef DEBUG #if DEBUG_LEVEL > 30 else perror("Unique ID: "+cookies->RoxenUserID+"\n"); #endif #endif not_query = simplify_path(not_query); return 1; // Done. } void disconnect() {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 2; #endif array err = catch { if(do_not_disconnect) {
b1fca01996-11-12Per Hedbor #ifdef REQUEST_DEBUG
ceb9271997-05-15David Hedbor  perror("REQUEST: Not disconnecting...\n");
b1fca01996-11-12Per Hedbor #endif
ceb9271997-05-15David Hedbor  return; }
b1fca01996-11-12Per Hedbor #ifdef REQUEST_DEBUG
ceb9271997-05-15David Hedbor  perror("REQUEST: Disconnecting...\n"); #endif if(mappingp(file) && objectp(file->file)) destruct(file->file); #if _DEBUG_HTTP_OBJECTS roxen->httpobjects[my_id] += " - disconnect";
b1fca01996-11-12Per Hedbor #endif
ceb9271997-05-15David Hedbor  my_fd = 0; }; if(err) roxen_perror("END: %O\n", describe_backtrace(err));
14179b1997-01-29Per Hedbor  destruct();
b1fca01996-11-12Per Hedbor }
14179b1997-01-29Per Hedbor #ifdef KEEP_CONNECTION_ALIVE
b1fca01996-11-12Per Hedbor void no_more_keep_connection_alive(mapping foo) { if(!pipe || !objectp(my_fd)) end(); }
14179b1997-01-29Per Hedbor #endif
b1fca01996-11-12Per Hedbor  void end(string|void s) {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 1; #endif array err = catch {
b1fca01996-11-12Per Hedbor #ifdef REQUEST_DEBUG
ceb9271997-05-15David Hedbor  perror("REQUEST: End...\n");
b1fca01996-11-12Per Hedbor #endif
14179b1997-01-29Per Hedbor #ifdef KEEP_CONNECTION_ALIVE
ceb9271997-05-15David Hedbor  remove_call_out(no_more_keep_connection_alive);
14179b1997-01-29Per Hedbor #endif
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS roxen->httpobjects[my_id] += " - end"; #endif if(objectp(my_fd)) { if(s) my_fd->write(s); destruct(my_fd); } }; if(err) roxen_perror("END: %O\n", describe_backtrace(err)); disconnect();
b1fca01996-11-12Per Hedbor }
ceb9271997-05-15David Hedbor static void do_timeout(mapping foo)
b1fca01996-11-12Per Hedbor {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 10; #endif // perror("Timeout. Closing down...\n"); #if _DEBUG_HTTP_OBJECTS roxen->httpobjects[my_id] += " - timed out"; #endif end((prot||"HTTP/1.0")+" 408 Timeout\n");
b1fca01996-11-12Per Hedbor }
14179b1997-01-29Per Hedbor #ifdef KEEP_CONNECTION_ALIVE
b1fca01996-11-12Per Hedbor void got_data(mixed fooid, string s); void keep_connection_alive() { pipe=0;
e118b81997-01-29Per Hedbor  my_fd->set_read_callback(got_data); my_fd->set_close_callback(end); /*my_fd->set_write_callback(lambda(){});*/
b1fca01996-11-12Per Hedbor  if(cache && strlen(cache)) got_data(1, ""); else call_out(no_more_keep_connection_alive, 100); }
14179b1997-01-29Per Hedbor #endif
b1fca01996-11-12Per Hedbor  mapping internal_error(array err) { if(QUERY(show_internals)) file = http_low_answer(500, "<h1>Error: Internal server error.</h1>" + "<font size=+1><pre>"+ describe_backtrace(err) + "</pre></font>"); else file = http_low_answer(500, "<h1>Error: The server failed to " "fulfill your query.</h1>"); report_error("Internal server error: " + describe_backtrace(err) + "\n"); }
23a7891996-12-15Per Hedbor int wants_more() { return !!cache; }
fc2fcf1997-04-13Per Hedbor constant errors = ([ 200:"200 OK", 201:"201 URI follows", 202:"202 Accepted", 203:"203 Provisional Information", 204:"204 No Content", 300:"300 Moved", 301:"301 Permanent Relocation", 302:"302 Temporary Relocation", 303:"303 Temporary Relocation method and URI", 304:"304 Not Modified", 400:"400 Bad Request", 401:"401 Access denied", 402:"402 Payment Required", 403:"403 Forbidden", 404:"404 No such file or directory.", 405:"405 Method not allowed", 407:"407 Proxy authorization needed", 408:"408 Request timeout", 409:"409 Conflict", 410:"410 This document is no more. It has gone to meet it's creator. It is gone. It will not be coming back. Give up. I promise. There is no such file or directory.", 500:"500 Internal Server Error.", 501:"501 Not Implemented", 502:"502 Gateway Timeout", 503:"503 Service unavailable", ]);
9f46de1997-04-08Per Hedbor void handle_request( )
b1fca01996-11-12Per Hedbor {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 15; #endif
b1fca01996-11-12Per Hedbor  mixed *err;
5bc1991997-01-29Per Hedbor  int tmp; #ifdef KEEP_CONNECTION_ALIVE int keep_alive; #endif
b1fca01996-11-12Per Hedbor  function funp; mapping heads;
5bc1991997-01-29Per Hedbor  string head_string;
14179b1997-01-29Per Hedbor  object thiso=this_object();
5bc1991997-01-29Per Hedbor 
b1fca01996-11-12Per Hedbor #ifndef SPEED_MAX
ceb9271997-05-15David Hedbor // perror("Removing timeout call_out...\n"); #if _DEBUG_HTTP_OBJECTS roxen->httpobjects[my_id] += " - handled"; #endif remove_call_out(do_timeout); remove_call_out(do_timeout);
b1fca01996-11-12Per Hedbor #endif
82f5191997-03-02Per Hedbor 
1e9c471997-02-27Marcus Comstedt  my_fd->set_read_callback(0); my_fd->set_close_callback(0);
b1fca01996-11-12Per Hedbor  if(conf) {
14179b1997-01-29Per Hedbor // perror("Handle request, got conf.\n"); foreach(conf->first_modules(), funp) if(file = funp( thiso)) break;
b1fca01996-11-12Per Hedbor 
14179b1997-01-29Per Hedbor  if(!file) err=catch(file = conf->get_file(thiso));
b1fca01996-11-12Per Hedbor  if(err) internal_error(err); if(!mappingp(file))
14179b1997-01-29Per Hedbor  foreach(conf->last_modules(), funp) if(file = funp(thiso)) break; } else if(err=catch(file = roxen->configuration_parse( thiso ))) { if(err==-1) return; internal_error(err); }
82f5191997-03-02Per Hedbor 
b1fca01996-11-12Per Hedbor  if(!mappingp(file)) {
f6d62d1997-03-26Per Hedbor  if(misc->error_code) file = http_low_answer(misc->error_code, errors[misc->error]); else if(method != "GET" && method != "HEAD" && method != "POST")
b1fca01996-11-12Per Hedbor  file = http_low_answer(501, "Not implemented."); else
14179b1997-01-29Per Hedbor  file=http_low_answer(404, replace(parse_rxml(conf->query("ZNoSuchFile"), thiso), ({"$File", "$Me"}), ({not_query, conf->query("MyWorldLocation")}))); } else { if((file->file == -1) || file->leave_me)
b1fca01996-11-12Per Hedbor  {
fc2fcf1997-04-13Per Hedbor  if(do_not_disconnect) return;
0ee0851997-02-08Per Hedbor // perror("Leave me...\n"); // if(!file->stay) { destruct(thiso); } my_fd = file = 0;
14179b1997-01-29Per Hedbor  return;
b1fca01996-11-12Per Hedbor  }
14179b1997-01-29Per Hedbor  if(file->type == "raw") file->raw = 1; else if(!file->type) file->type="text/plain"; }
b1fca01996-11-12Per Hedbor  if(!file->raw && prot != "HTTP/0.9") { string h; heads= ([ "Content-type":file["type"],
e118b81997-01-29Per Hedbor  "Server":version(), "Date":http_date(time) ]);
b1fca01996-11-12Per Hedbor  if(file->encoding) heads["Content-Encoding"] = file->encoding; if(!file->error) file->error=200; if(file->expires) heads->Expires = http_date(file->expires); if(!file->len) { if(objectp(file->file))
14179b1997-01-29Per Hedbor  if(!file->stat && !(file->stat=misc->stat))
b1fca01996-11-12Per Hedbor  file->stat = (int *)file->file->stat(); array fstat; if(arrayp(fstat = file->stat)) { if(file->file && !file->len) file->len = fstat[1]; heads["Last-Modified"] = http_date(fstat[3]); if(since) { if(is_modified(since, fstat[3], fstat[1])) { file->error = 304; method="HEAD"; } } } if(stringp(file->data)) file->len += strlen(file->data); } #ifdef KEEP_CONNECTION_ALIVE #ifdef REQUEST_DEBUG if(kept_alive) perror(sprintf("Connection: Kept alive %d times.\n", kept_alive)); #endif if(misc->connection && search(misc->connection, "keep-alive") != -1) { if(file->len > 0) { heads->Connection = "keep-alive; timeout=100, maxreq=666"; keep_alive=1; #ifdef REQUEST_DEBUG kept_alive++; #endif } } #endif if(mappingp(file->extra_heads)) heads |= file->extra_heads; if(mappingp(misc->moreheads)) heads |= misc->moreheads;
14179b1997-01-29Per Hedbor  array myheads = ({prot+" "+(file->rettext||errors[file->error])});
b1fca01996-11-12Per Hedbor  foreach(indices(heads), h) if(arrayp(heads[h])) foreach(heads[h], tmp)
5e89211997-02-13Per Hedbor  myheads += ({ `+(h,": ", tmp)});
b1fca01996-11-12Per Hedbor  else
5e89211997-02-13Per Hedbor  myheads += ({ `+(h, ": ", heads[h])});
b1fca01996-11-12Per Hedbor  if(file->len > -1)
14179b1997-01-29Per Hedbor  myheads += ({"Content-length: " + file->len }); head_string = (myheads+({"",""}))*"\r\n";
b1fca01996-11-12Per Hedbor 
14179b1997-01-29Per Hedbor  if(conf)conf->hsent+=strlen(head_string||"");
5bc1991997-01-29Per Hedbor 
b1fca01996-11-12Per Hedbor  if(method=="HEAD") {
14179b1997-01-29Per Hedbor  if(conf)conf->log(file, thiso);
5bc1991997-01-29Per Hedbor #ifdef KEEP_CONNECTION_ALIVE
b1fca01996-11-12Per Hedbor  if(keep_alive) { my_fd->write(head_string); misc->connection = 0; keep_connection_alive();
5bc1991997-01-29Per Hedbor  } else
14179b1997-01-29Per Hedbor #endif
b1fca01996-11-12Per Hedbor  end(head_string); return; }
14179b1997-01-29Per Hedbor  if(conf) conf->sent+=(file->len>0 ? file->len : 1000);
82f5191997-03-02Per Hedbor 
5bc1991997-01-29Per Hedbor  if(!file->data && (file->len<=0 || (file->len > 30000)) #ifdef KEEP_CONNECTION_ALIVE && !keep_alive #endif && objectp(file->file))
b1fca01996-11-12Per Hedbor  {
5bc1991997-01-29Per Hedbor  if(head_string) my_fd->write(head_string);
14179b1997-01-29Per Hedbor  shuffle( file->file, my_fd ); if(conf)conf->log(file, thiso); my_fd=file->file=file=pipe=0;
5bc1991997-01-29Per Hedbor  destruct(thiso); return;
b1fca01996-11-12Per Hedbor  }
82f5191997-03-02Per Hedbor 
5bc1991997-01-29Per Hedbor  if(file->len < 3000 && #ifdef KEEP_CONNECTION_ALIVE !keep_alive && #endif file->len >= 0)
b1fca01996-11-12Per Hedbor  {
82f5191997-03-02Per Hedbor 
e118b81997-01-29Per Hedbor  if(file->data) head_string += file->data; if(file->file) { head_string += file->file->read(file->len); destruct(file->file); } if(conf) conf->log(file, thiso); end(head_string); return; }
14179b1997-01-29Per Hedbor  }
e118b81997-01-29Per Hedbor 
b1fca01996-11-12Per Hedbor  if(head_string) send(head_string); if(file->data) send(file->data); if(file->file) send(file->file); pipe->output(my_fd);
14179b1997-01-29Per Hedbor  if(conf) conf->log(file, thiso);
b1fca01996-11-12Per Hedbor  #ifdef KEEP_CONNECTION_ALIVE if(keep_alive) { if(my_fd) {
14179b1997-01-29Per Hedbor  misc->connection=0;
b1fca01996-11-12Per Hedbor  pipe->set_done_callback(keep_connection_alive); }
14179b1997-01-29Per Hedbor  } else #endif
5bc1991997-01-29Per Hedbor  {
14179b1997-01-29Per Hedbor  my_fd=0;
5bc1991997-01-29Per Hedbor  pipe=file=0; destruct(thiso); }
14179b1997-01-29Per Hedbor } /* We got some data on a socket. * ================================================= */ void got_data(mixed fooid, string s) { int tmp;
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 3; #endif
14179b1997-01-29Per Hedbor // perror("Got data.\n"); #ifndef SPEED_MAX
ceb9271997-05-15David Hedbor // perror("Removing timeout call_out...\n"); #if _DEBUG_HTTP_OBJECTS roxen->httpobjects[my_id] = ("Got data - "+remoteaddr +" - "+ctime(_time())) - "\n"; #endif remove_call_out(do_timeout); remove_call_out(do_timeout); call_out(do_timeout, 60); // Close down if we don't get more data // within 30 seconds. Should be more than enough. call_out(do_timeout, 70);// There seems to be a bug where call_outs go missing...
14179b1997-01-29Per Hedbor #endif if(wanted_data) { if(strlen(s)+have_data < wanted_data) { cache += ({ s }); have_data += strlen(s); return; } } if(cache) { cache += ({ s }); s = cache*""; cache = 0; } #ifdef KEEP_CONNECTION_ALIVE remove_call_out(no_more_keep_connection_alive); #endif tmp = parse_got(s); switch(-tmp) { case 0: cache = ({ s }); // More on the way. return; case 1: end(prot+" 500 Stupid Client Error\r\nContent-Length: 0\r\n\r\n"); return; // Stupid request. case 2: end(); return; }
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS roxen->httpobjects[my_id] += " - finished getting data."; #endif
14179b1997-01-29Per Hedbor  if(conf) { conf->received += strlen(s); conf->requests++; } #ifdef THREADS
9f46de1997-04-08Per Hedbor  handle(this_object()->handle_request);
14179b1997-01-29Per Hedbor #else
9f46de1997-04-08Per Hedbor  this_object()->handle_request();
b1fca01996-11-12Per Hedbor #endif } /* Get a somewhat identical copy of this object, used when doing * 'simulated' requests. */ object clone_me() {
14179b1997-01-29Per Hedbor  object c,t;
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 4; #endif
14179b1997-01-29Per Hedbor  c=object_program(t=this_object())();
b1fca01996-11-12Per Hedbor 
f6d62d1997-03-26Per Hedbor  c->first = first;
b1fca01996-11-12Per Hedbor  c->conf = conf; c->time = time;
f6d62d1997-03-26Per Hedbor  c->raw_url = raw_url; // c->do_not_disconnect = do_not_disconnect; // No use where there is no fd.. c->variables = copy_value(variables);
48fa361997-04-05Per Hedbor  c->misc = copy_value(misc); c->misc->orig = t;
f6d62d1997-03-26Per Hedbor 
b1fca01996-11-12Per Hedbor  c->prestate = prestate; c->supports = supports;
f6d62d1997-03-26Per Hedbor  c->config = config;
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; // file.. c->my_fd = 0; // pipe.. c->prot = prot; c->method = method; // realfile virtfile // Should not be copied. c->rest_query = rest_query; c->raw = raw; c->query = query; c->not_query = not_query; c->extra_extension = extra_extension; c->data = data;
b1fca01996-11-12Per Hedbor  c->auth = auth; c->realauth = realauth;
f6d62d1997-03-26Per Hedbor  c->rawauth = rawauth; c->since = since;
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS if(!c->my_id) c->my_id = roxen->new_id(); roxen->httpobjects[c->my_id] = roxen->httpobjects[my_id] + " - clone"; roxen->httpobjects[my_id] += " - CLONED"; #endif
b1fca01996-11-12Per Hedbor  return c; } void clean() {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS my_state = 4; #endif
b1fca01996-11-12Per Hedbor  if(!(my_fd && objectp(my_fd))) end(); else if((_time(1) - time) > 4800) end(); }
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS void destroy() { roxen->httpobjects->num--; m_delete(roxen->httpobjects, my_id); } #endif
14179b1997-01-29Per Hedbor void create(object f, object c)
b1fca01996-11-12Per Hedbor {
ceb9271997-05-15David Hedbor  #if _DEBUG_HTTP_OBJECTS my_state = 5; roxen->httpobjects->num++; #endif
14179b1997-01-29Per Hedbor  if(f) {
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS if(!my_id) my_id = roxen->new_id(); #endif
14179b1997-01-29Per Hedbor  my_fd = f;
e118b81997-01-29Per Hedbor  my_fd->set_read_callback(got_data); my_fd->set_close_callback(end);
ceb9271997-05-15David Hedbor #if _DEBUG_HTTP_OBJECTS catch(remoteaddr = ((my_fd->query_address()||"")/" ")[0]); roxen->httpobjects[my_id] = ("Created - "+ remoteaddr +" - "+ctime(_time())) - "\n" ; #endif
14179b1997-01-29Per Hedbor  conf = c; mark_fd(my_fd->query_fd(), "HTTP connection");
b1fca01996-11-12Per Hedbor #ifndef SPEED_MAX
ceb9271997-05-15David Hedbor  // No need to wait more than 30 seconds to get more data. call_out(do_timeout, 60); call_out(do_timeout, 70); // There seems to be a bug where call_outs go missing...
b1fca01996-11-12Per Hedbor #endif
14179b1997-01-29Per Hedbor  }
b1fca01996-11-12Per Hedbor }
ceb9271997-05-15David Hedbor