Roxen.git / server / plugins / protocols / http.pike

version» Context lines:

Roxen.git/server/plugins/protocols/http.pike:1:   // This is a ChiliMoon protocol module.   // Modified by Francesco Chemolli to add throttling capabilities.   // Copyright © 1996 - 2001, Roxen IS.    - constant cvs_version = "$Id: http.pike,v 1.414 2004/07/06 09:06:56 _cvs_stephen Exp $"; + constant cvs_version = "$Id: http.pike,v 1.415 2005/04/14 23:06:59 _cvs_dirix Exp $";   //#define REQUEST_DEBUG   //#define CONNECTION_DEBUG   #define MAGIC_ERROR   #define HTTPTIMEOUT 90      // HTTP protocol module.   #include <config.h>   #define TIMER_PREFIX "http:"   #include <timers.h>   #include <stat.h>      inherit RequestID;      #ifdef PROFILE   #define HRTIME() gethrtime()   int req_time = HRTIME();   #endif    - #ifdef ID_OBJ_DEBUG - RoxenDebug.ObjectMarker __marker = RoxenDebug.ObjectMarker(this); - #endif -  +    #ifdef REQUEST_DEBUG   int footime, bartime;   #define REQUEST_WERR(X) do {bartime = gethrtime()-footime; werror("%s (%d)\n", (X), bartime);footime=gethrtime();} while (0)   #else   #define REQUEST_WERR(X) do {} while (0)   #endif      #ifdef FD_DEBUG -  + #ifdef REQUEST_DEBUG + #define FD_WERR(X) REQUEST_WERR(X) + #else + #define FD_WERR(X) werror("%s\n", (X)) + #endif   #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)); \ -  +  FD_WERR("FD " + (_fd == -1 ? sprintf ("%O", my_fd) : _fd) + ": " + (X)); \    mark_fd(_fd, (X)+" "+remoteaddr); \    } while (0)   #else   #define MARK_FD(X) do {} while (0)   #endif      #ifdef THROTTLING_DEBUG   #undef THROTTLING_DEBUG   #define THROTTLING_DEBUG(X) werror("Throttling: "+X+"\n")   #else
Roxen.git/server/plugins/protocols/http.pike:61:   private static multiset(string) none_match;      int kept_alive;      #ifdef DEBUG   #define CHECK_FD_SAFE_USE do { \    if (this_thread() != core->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"); \ +  error ("Got callbacks but not called from backend thread.\n" \ +  "rcb:%O\n" \ +  "wcb:%O\n" \ +  "ccb:%O\n" \ +  "timeout:%O\n", \ +  my_fd->query_read_callback(), \ +  my_fd->query_write_callback(), \ +  my_fd->query_close_callback(), \ +  find_call_out (do_timeout)); \    } while (0)   #else   #define CHECK_FD_SAFE_USE do {} while (0)   #endif      #include <roxen.h>   #include <module.h>   #include <variables.h>   #include <request_trace.h>   
Roxen.git/server/plugins/protocols/http.pike:282:    else    rest_query = http_decode_string( v );    rest_query=replace(rest_query, "+", "\000"); /* IDIOTIC STUPID STANDARD */    }    return f;   }      private static mixed f, line;   private static int hstart;    - //! Parse a cookie string. + //! Parse a cookie strings.   //!   //! @param contents - //! HTTP transport-encoded cookie header value. + //! HTTP transport-encoded cookie header value or array with values.   //!   //! @returns   //! Returns the resulting current cookie mapping. - mapping(string:string) parse_cookies( string contents ) + mapping(string:string) parse_cookies( array|string contents )   {    if(!contents)    return cookies;      // misc->cookies += ({contents}); -  foreach(((contents/";") - ({""})), string c) +  +  array tmp = arrayp(contents) ? contents : ({ contents}); +  +  foreach(tmp, string cookieheader) { +  +  foreach(((cookieheader/";") - ({""})), 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;    }    } -  +  }    return cookies;   }      int things_to_do_when_not_sending_from_cache( )   {    array|string contents;    misc->pref_languages=PrefLanguages();       misc->cachekey = CacheKey();    misc->_cachecallbacks = ({});
Roxen.git/server/plugins/protocols/http.pike:401:    {    // The Proxy-authorization header should be removed... So there.    mixed tmp1,tmp2;       foreach(tmp2 = (raw / "\n"), tmp1) {    if(has_prefix(lower_case(tmp1), "proxy-authorization:"))    tmp2 -= ({tmp1});    }    raw = tmp2 * "\n";    } -  if(!supports->cookies) +  if(!supports->cookies && !sizeof(config))    config = prestate;    else    if( port_obj->set_cookie    && !cookies->ChiliMoonUserID && sizeof(not_query)    && 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)
Roxen.git/server/plugins/protocols/http.pike:685:    real_variables[part->disp_params->name] += ({part->getdata()});    if(part->headers["content-type"])    real_variables[part->disp_params->name+".mimetype"] +=    ({ part->headers["content-type"] });    }    stash_body_parts = real_variables + ([ ]);    }    break;    }    } +  } else { +  leftovers = data;    }    TIMER_END(parse_got_2_more_data);    if (!(< "HTTP/1.0", "HTTP/0.9" >)[prot]) {    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"
Roxen.git/server/plugins/protocols/http.pike:722:    misc->cacheable = t;    return ot;   }      void disconnect()   {    file = 0;    conf && conf->connection_drop( this );    if (my_fd) {    MARK_FD("HTTP my_fd in HTTP disconnected?"); -  catch(my_fd->close()); +  if (mixed err = catch (my_fd->close())) { + #ifdef DEBUG +  report_debug ("Failed to close http(s) connection: " + +  describe_error (err)); +  #endif +  }    my_fd = 0;    }    MERGE_TIMERS(conf); -  if(do_not_disconnect) return; +     destruct();   }      static void cleanup_request_object()   {    if( conf )    conf->connection_drop( this ); -  +  xml_data = 0;   }      void end(int|void keepit)   {    CHECK_FD_SAFE_USE;       remove_call_out(do_timeout);    cleanup_request_object();       if(keepit
Roxen.git/server/plugins/protocols/http.pike:776:    pipe = 0;    disconnect();    return;    }       data_buffer = 0;    pipe = 0;    disconnect();   }    + static void close_cb() + { + #ifdef CONNECTION_DEBUG +  werror ("HTTP: Client close ---------------------------------------------\n") + ; + #else +  REQUEST_WERR ("HTTP: Got remote close."); + #endif +  +  CHECK_FD_SAFE_USE; +  +  cleanup_request_object(); +  +  data_buffer = 0; +  pipe = 0; +  +  // Avoid that the fd is closed by disconnect() - the write direction +  // might still want to use it. We rely on refcount garbing instead. +  my_fd = 0; +  +  disconnect(); + } +    static void do_timeout()   {    int elapsed = predef::time(1)-time;    if(time && elapsed >= HTTPTIMEOUT/3)    { -  REQUEST_WERR("HTTP: Connection timed out. Closing."); + #ifdef CONNECTION_DEBUG +  werror("HTTP: Connection timed out. Closing.\n" +  "rcb:%O\n" +  "wcb:%O\n" +  "ccb:%O\n", +  my_fd->query_read_callback(), +  my_fd->query_write_callback(), +  my_fd->query_close_callback()); + #else +  REQUEST_WERR(sprintf("HTTP: Connection timed out. Closing.\n" +  "rcb:%O\n" +  "wcb:%O\n" +  "ccb:%O\n", +  my_fd->query_read_callback(), +  my_fd->query_write_callback(), +  my_fd->query_close_callback())); + #endif    MARK_FD("HTTP timeout");    end();    } else {   #ifdef DEBUG    error ("This shouldn't happen.\n");   #endif    // premature call_out... *¤#!"    call_out(do_timeout, 10);    MARK_FD("HTTP premature timeout");    }   }      string link_to(string file, int line, string fun, int eid, int qq)   {    if (!file || !line) return "<a>"; -  if(file[0]!='/') file = combine_path(getcwd(), file); +     return ("<a href=\"/(old_error,find_file)/error/?"+    "file="+Roxen.http_encode_url(file)+    (fun ? "&fun="+Roxen.http_encode_url(fun) : "") +    "&off="+qq+    "&error="+eid+    "&error_md5="+get_err_md5(get_err_info(eid))+    (line ? "&line="+line+"#here" : "") +    "\">");   }    - static string error_page_header (string title) + static string error_page(string line1, string title, string body)   { -  title = Roxen.html_encode_string (title); -  return #"<html><head><title>" + title + #"</title></head> - <body bgcolor='white' text='black' link='#ce5c00' vlink='#ce5c00'> - <table width='100%'><tr> - <td><a href='http://www.roxen.com/'><imgs border='0' src='/$/roxen-small' /></a></td> - <td><b><font size='+1'>" + title + #"</font></b></td> - <td align='right'><font size='+1'>ChiliMoon " + Roxen.html_encode_string (roxen_version()) + #"</font></td> - </tr></table> -  - "; +  return #"\ + <html><head> +  <title>Internal Server Error</title> +  <style> +  .msg { font-family: verdana, helvetica, arial, sans-serif; +  font-size: 12px; +  line-height: 160% } +  .big { font-family: georgia, times, serif; +  font-size: 18px; +  padding-top: 6px; +  padding-bottom: 20px } +  .info { font-family: verdana, helvetica, arial, sans-serif; +  font-size: 10px; +  color: #999999 } +  .list { padding-left: 20px; +  list-style-type:square; } +  .code { font-family: monaco, courier, monospace; +  font-size: 10px; +  color: #404070; } +  </style> + </head> + <body text='#000000' style='margin: 0; padding: 0' vlink='#2331d1' +  rightmargin='0' leftmargin='0' alink='#f6f6ff' link='#0000ee' +  bgcolor='#f2f1eb' bottommargin='0' topmargin='0'> + <table border='0' cellspacing='0' cellpadding='0' height='99%'> +  <tr> +  <td><img src='/internal-roxen-unit' height='30' /></td> +  </tr><tr> +  <td></td> +  <td><img src='/$/chilimoon-black' /></td> +  <td><img src='/$/unit' width='30' /></td> +  <td valign='bottom'><img src='/$/internal-roxen-server-error' /></td> +  </tr><tr> +  <td><img src='/$/unit' height='30' /></td> +  </tr><tr> +  <td colspan='3'></td> +  <td> +  <div class='msg'>" + line1 + #"</div> +  <div class='big'>" + title + #"</div> +  </td> +  </tr><tr> +  <td></td> +  <td colspan='3'> +  <div class='msg'>" + body + #"</div> +  </td> +  </tr><tr valign='bottom' height='100%'> +  <td colspan='4' align='right'> +  <img src='/$/unit' height='20' /> +  <table border='0' cellspacing='0' cellpadding='0'> +  <tr> +  <td><img src='/$/chili-small-black.gif' /></td> +  <td class='info'> +  &nbsp;&nbsp;<b>" + roxen_product_name + #"</b> +  <font color='#ffbe00'>|</font> " + roxen_dist_version + #" +  </td> +  </tr> +  </table> +  <img src='/$/unit' height='15' /> +  </td> +  </tr> + </table> + </body></html>";   }      static string get_err_md5(array(string|array(string)|array(array)) err_info)   {    if (err_info) {    return String.string2hex(Crypto.MD5.hash(err_info[3]));    }    return "NONE";   }   
Roxen.git/server/plugins/protocols/http.pike:850:    }    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"); +  return error_page("Unregistered error", "", "");    }       [string msg, array(string) rxml_bt, array(array) bt,    string raw_bt_descr, string raw_url, string raw] = err_info;    -  string res = error_page_header ("Internal Server Error") + -  "<h1>" + replace (Roxen.html_encode_string (msg), "\n", "<br />\n") + "</h1>\n"; +  string title = replace(Roxen.html_encode_string(msg), "\n", "<br />\n"); +  string body = "";       if (rxml_bt && sizeof (rxml_bt)) { -  res += "<h3>RXML frame backtrace</h3>\n<ul>\n"; -  foreach (rxml_bt, string line) -  res += "<li>" + Roxen.html_encode_string (line) + "</li>\n"; -  res += "</ul>\n\n"; +  body += +  "RXML frame backtrace" +  "<ul class='list'>"; +  foreach(rxml_bt, string line) +  body += "<li class='code'>" + Roxen.html_encode_string(line) + "</li>\n"; +  body += "</ul>\n";    }       if (bt && sizeof (bt)) { -  res += "<h3>Pike backtrace</h3>\n<ul>\n"; +  body += +  "Pike backtrace" +  "<ul class='list'>";    int q = sizeof (bt);    foreach(bt, [string file, int line, string func, string descr])    {   #if constant(PIKE_MODULE_RELOC)    file = file && master()->relocate_module(file);   #endif -  res += "<li value="+(q--)+">" + -  link_to (file, line, func, eid, q) + -  (file ? Roxen.html_encode_string (file) : "<i>Unknown program</i>") + +  q--; +  body += +  "<li>" + +  link_to(file, line, func, eid, q) + // inserts <a> +  (file ? Roxen.html_encode_string(file) : "<i>Unknown program</i>") +    (line ? ":" + line : "") +    "</a>" + (file ? Roxen.html_encode_string (get_cvs_id (file)) : "") + ":<br />\n" + -  replace (Roxen.html_encode_string (descr), -  ({"(", ")", " "}), ({"<b>(</b>", "<b>)</b>", "&nbsp;"})) + -  "</li>\n"; +  "</a>" + +  (file ? Roxen.html_encode_string(get_cvs_id(file)) : "") + +  "<br /><span class='code'>" + +  replace(Roxen.html_encode_string(descr), " ", "&nbsp;") + +  "</span></li>\n";    } -  res += "</ul>\n\n"; +  body += "</ul>\n\n";    }    -  res += ("<p><b><a href=\"/(old_error,plain)/error/?" -  "error="+eid+ -  "&error_md5="+get_err_md5(get_err_info(eid))+ +  body += +  "<p>Generate " +  "<a href=\"/(old_error,plain)/error/?" +  "error=" + eid + +  "&error_md5=" + get_err_md5(get_err_info(eid)) +    "\">" -  "Generate text only version of this error message, for bug reports"+ -  "</a></b></p>\n\n"); -  return res+"</body></html>"; +  "text-only version</a> of this error message for bug reports.</p>"; +  return error_page("The server failed to fulfill your query.", title, body);   }      string generate_bugreport(string msg, array(string) rxml_bt, array(string) bt,    string raw_bt_descr, string raw_url, string raw)   { -  return ("ChiliMoon version: "+version()+ -  (core.real_version != version()? +  return ("ChiliMoon version: "+core.version()+ +  (core.real_version != core.version()?    " ("+core.real_version+")":"")+    "\nPike version: " + predef::version() +    "\nRequested URL: "+raw_url+"\n"    "\nError: " + raw_bt_descr +    "\nRequest data:\n"+raw);   }      string censor(string what)   {    string a, b, c;
Roxen.git/server/plugins/protocols/http.pike:1026:    array err2;    if(port_obj && port_obj->query("show_internals"))    {    err2 = catch {    file = Roxen.http_low_answer(500, format_backtrace(store_error(err)));    };    if(err2) {    werror("Internal server error in internal_error():\n" +    describe_backtrace(err2)+"\n while processing \n"+    describe_backtrace(err)); -  file = Roxen.http_low_answer(500, "<h1>Error: The server failed to " -  "fulfill your query, due to an " -  "internal error in the internal error routine.</h1>"); +  file = +  Roxen.http_low_answer(500, error_page("The server failed to fulfill " +  "your query due to an internal " +  "error in the internal error " +  "routine.", "", ""));   }    } else { -  file = Roxen.http_low_answer(500, "<h1>Error: The server failed to " -  "fulfill your query, due to an internal error.</h1>"); +  file = +  Roxen.http_low_answer(500, error_page("The server failed to fulfill " +  "your query.", "", ""));    }    report_error("Internal server error: " +    describe_backtrace(err) + "\n");   #ifdef INTERNAL_ERROR_DEBUG    report_error("Raw backtrace:%O\n", err);   #endif /* INTERNAL_ERROR_DEBUG */   }      // This macro ensures that something gets reported even when the very   // call to internal_error() fails. That happens eg when "this" has been
Roxen.git/server/plugins/protocols/http.pike:1055:    if (mixed __eRr = catch (internal_error (err))) \    report_error("Internal server error: " + describe_backtrace(err) + \    "internal_error() also failed: " + describe_backtrace(__eRr)); \    } while (0)      int wants_more()   {    return !!cache;   }    + static object(this_program) chained_to; +  + // Paranoia. + static void destroy() + { +  if (chained_to) { +  werror("HTTP: Still chained in destroy!\n"); +  call_out(chained_to->my_fd_released, 0); +  chained_to = 0; +  } + } +    void do_log(int fsent)   { -  + #ifdef CONNECTION_DEBUG +  werror ("HTTP: Response sent ============================================\n") + ; + #endif    MARK_FD("HTTP logging"); // fd can be closed here -  +  if (chained_to) { +  // Release the other sender. +  call_out(chained_to->my_fd_released, 0); +  chained_to = 0; +  }    TIMER_START(do_log);    if(conf)    {    conf->sent+=fsent;    file->len += misc->_log_cheat_addition;    conf->log(file, this);    }       if( !port_obj )    {
Roxen.git/server/plugins/protocols/http.pike:1108: Inside #if defined(FD_DEBUG)
   } else {    MARK_FD("HTTP piping, but no pipe for "+not_query);    }    call_out(timer, 30, start);   }   #endif      string handle_error_file_request (string msg, array(string) rxml_bt, array(array) bt,    string raw_bt_descr, string raw_url, string raw)   { -  string data = Stdio.read_bytes(variables->file); -  +  // Check that the file is valid and is present in the backtrace. +  string data; +  foreach(bt, array frame) { +  if (frame[0] == variables->file) { +  data = Stdio.read_bytes(variables->file); +  break; +  } +  }    if(!data) -  return error_page_header (variables->file) + -  "<h3><i>Source file could not be read</i></h3>\n" -  "</body></html>"; +  return error_page("Source file could not be read:", variables->file, "");       string down;    int next = (int) variables->off + 1;       if(next < sizeof (bt)) {    [string file, int line, string func, string descr] = bt[next];    down = link_to (file, line, func, (int) variables->error, next);    }    else    down = "<a>";
Roxen.git/server/plugins/protocols/http.pike:1140:    off += start;    start = 0;    }    int end = (int)variables->line+50;       lines = map (lines[start..end], Roxen.html_encode_string);       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>"; +  lines[off] = indent + "<font size='+1'><b>"+down+code+"</a></b></font>";    }    lines[max(off-20,0)] = "<a name=here>"+lines[max(off-20,0)]+"</a>"; -  -  return error_page_header (variables->file) + -  "<font size='-1'><pre>" + lines*"\n" + "</pre></font>\n" -  "</body></html>"; +  return error_page("Source code for", variables->file, +  "<span class='code'><pre>" + +  (lines * "\n") + +  "</pre></span>");   }      // The wrapper for multiple ranges (send a multipart/byteranges reply).   #define BOUND "Byte_Me_Now_Chily"      class MultiRangeWrapper   {    object file;    function rcb;    int current_pos, len, separator;
Roxen.git/server/plugins/protocols/http.pike:1368:    file = Roxen.http_status(misc->error_code, errors[misc->error]);    else if(err = catch {    file = conf->error_file( this );    })    INTERNAL_ERROR(err);    }    else    {    if((file->file == -1) || file->leave_me)    { -  TIMER_END(send_result); +  TIMER_END(send_result)    file = 0;    pipe = 0;    if(do_not_disconnect)    return;    my_fd = 0;    return;    }       if(file->type == "raw") file->raw = 1;    }
Roxen.git/server/plugins/protocols/http.pike:1514:    // Reply with a 416 Requested Range not satisfiable.    file->error = 416;    heads["Content-Range"] = "*/"+file->len;    if(method == "GET") {    file->file = file->data = file->type = file->len = 0;    }    }    }    }    } -  +     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";    } -  +  // Check for wide headers. +  // FIXME: Assumes no header names are wide. +  foreach(heads; string header_name; string content) { +  if (String.width(content) > 8) { +  array(array(string)|int) tokenized = +  MIME.decode_words_tokenized(string_to_utf8(content)); +  foreach(tokenized, array(string)|int token) { +  if (arrayp(token)) { +  string raw = utf8_to_string(token[0]); +  if (String.width(raw) > 8) { +  if (token[1]) { +  // Should not happen in normal circumstances. +  catch { +  // Attempt to recode in UTF-8. +  token[0] = string_to_utf8(Locale.Charset. +  decoder(token[1])-> +  feed(raw)->drain()); +  }; +  } +  token[1] = "utf-8"; +  } else { +  token[0] = raw; +  } +  } +  } +  string q = MIME.encode_words_quoted(tokenized, "q"); +  string b = MIME.encode_words_quoted(tokenized, "b"); +  // Prefer QP to BASE-64 if they are the same length. +  heads[header_name] = (sizeof(b)<sizeof(q))?b:q; +  } +  }       if( mixed err = catch( head_string += Roxen.make_http_headers( heads ) ) )    {   #ifdef DEBUG    report_debug ("Roxen.make_http_headers failed: " +    describe_error (err));   #endif    foreach(heads; string x; string|array(string) val) {    if (stringp(val))    head_string += x+": "+val+"\r\n";
Roxen.git/server/plugins/protocols/http.pike:1551:    foreach( val, string xx )    head_string += x+": "+xx+"\r\n";    else if( catch {    head_string += x+": "+(string)val+"\r\n";    } )    error("Illegal value in headers array! "    "Expected string or array(string)\n");    }    head_string += "\r\n";    } -  -  if (sscanf (heads["Content-Type"], "; charset=%s", string charset) || -  String.width( head_string ) > 8 ) -  head_string = output_encode( head_string, 0, charset )[1]; +     conf->hsent += sizeof(head_string);    }    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    MARK_FD("HTTP handled");       if( (method!="HEAD") && (file->error!=204) )    // No data for these two...    {   #ifdef RAM_CACHE    if( (misc->cacheable > 0) && (file->data || file->file) &&    (prot != "HTTP/0.9") && !misc->no_proto_cache)    {    if( file->len>0 && // known length.    ((file->len + sizeof( head_string )) <    conf->datacache->max_file_size) -  +  // vvv Relying on the interpreter lock from here.    && misc->cachekey )    { -  +  misc->cachekey->activate(); +  // ^^^ Relying on the interpreter lock to here.    string data = "";    if( file->file ) data += file->file->read();    if( file->data ) data += file->data;    MY_TRACE_ENTER (sprintf ("Storing in ram cache, entry: %O", raw_url), 0);    MY_TRACE_LEAVE ("");    conf->datacache->set( raw_url, data,    ([    // We have to handle the date header.    "hs":head_string,    "key":misc->cachekey,
Roxen.git/server/plugins/protocols/http.pike:1636:    TIMER_END(blocking_write);    do_log(s);    return;    }    if(sizeof(head_string)) send(head_string);    if(file->data && sizeof(file->data)) send(file->data, file->len);    if(file->file) send(file->file, file->len);    }    else    { -  if( sizeof( head_string ) < (HTTP_BLOCKING_SIZE_THRESHOLD)) +  if( !kept_alive && +  (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
Roxen.git/server/plugins/protocols/http.pike:1772:       if (string p = misc->site_prefix_path) cached_url_base += p;    cached_url_base += "/";    }    return cached_url_base;   }      /* We got some data on a socket.    * =================================================    */ - int processed; +    // array ccd = ({}); - void got_data(mixed fooid, string s) + void got_data(mixed fooid, string s, void|int chained)   {   #ifdef CONNECTION_DEBUG    werror ("HTTP: Request --------------------------------------------------\n"    "%s\n",    replace (sprintf ("%O", s),    ({"\\r\\n", "\\n", "\\t"}),    ({"\n", "\n", "\t"})));   #else    REQUEST_WERR(sprintf("HTTP: Got %O", s));   #endif
Roxen.git/server/plugins/protocols/http.pike:1801:    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);    have_data += sizeof(s);    +  REQUEST_WERR("HTTP: We want more data."); +     // Reset timeout.    remove_call_out(do_timeout);    call_out(do_timeout, HTTPTIMEOUT); -  REQUEST_WERR("HTTP: We want more data."); +  +  if (chained) +  my_fd->set_nonblocking(got_data, 0, close_cb);    return;    }    if(data_buffer) {    data_buffer->add(s);    data = (string)data_buffer;    data_buffer = 0;    }    else    data += s;    }
Roxen.git/server/plugins/protocols/http.pike:1835:    conf->connection_drop( this );    MARK_FD ("HTTP: Port closed.");    call_out (disconnect, 0);    return;    }       switch( parse_got( s ) )    {    case 0:    REQUEST_WERR("HTTP: Request needs more data."); +  if (chained) +  my_fd->set_nonblocking(got_data, 0, close_cb);    return;       case 1:    REQUEST_WERR("HTTP: Stupid Client Error.");    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.
Roxen.git/server/plugins/protocols/http.pike:1859:    return;    }      #ifdef CONNECTION_DEBUG    werror ("HTTP: Request received -----------------------------------------\n");   #endif       if( method == "GET" || method == "HEAD" ) {    misc->cacheable = INITIAL_CACHEABLE; // FIXME: Make configurable.   #ifdef DEBUG_CACHEABLE -  report_debug("===> Request for %s initiated cacheable to %d.\n", raw_url, -  misc->cacheable); +  report_debug("<=== Request for %s returned cacheable %d (proto cache %s).\n", +  raw_url, misc->cacheable, +  misc->no_proto_cache ? "disabled" : "enabled");   #endif    }       TIMER_START(find_conf);    string path;    if( !conf || !(path = port_obj->path )    || (sizeof( path )    && raw_url[..sizeof(path) - 1] != path) )       {
Roxen.git/server/plugins/protocols/http.pike:1946:    if( conf )    {    conf->connection_add( this, ([]) );    conf->received += sizeof(raw);    conf->requests++;    }    CHECK_FD_SAFE_USE;    my_fd->set_close_callback(0);    my_fd->set_read_callback(0);    if (my_fd->set_accept_callback) my_fd->set_accept_callback(0); -  processed=1; +        remove_call_out(do_timeout);   #ifdef RAM_CACHE    TIMER_START(cache_lookup);    array cv;    if( prot != "HTTP/0.9" &&    misc->cacheable &&    !misc->no_proto_cache &&    !since &&    (cv = conf->datacache->get( raw_url )) )
Roxen.git/server/plugins/protocols/http.pike:2061:    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));    TIMER_END(parse_request);       REQUEST_WERR("HTTP: Calling core.handle().");    core.handle(handle_request);    })    {    report_error("Internal server error: " + describe_backtrace(err)); -  my_fd->set_blocking(); -  my_fd->close(); -  my_fd = 0; +     disconnect();    }   }      /* Get a somewhat identical copy of this object, used when doing    * 'simulated' requests. */      this_program clone_me()   {    this_program c=this_program(0, port_obj, conf);
Roxen.git/server/plugins/protocols/http.pike:2136:    end();    else if((predef::time(1) - time) > 4800)    end();   }      static void create(object f, object c, object cc)   {    if(f)    {    f->set_nonblocking(got_data, f->query_write_callback(), end); +  f->set_nonblocking(got_data, f->query_write_callback(), close_cb);    my_fd = f;    CHECK_FD_SAFE_USE;    MARK_FD("HTTP connection");    if( c ) port_obj = c;    if( cc ) conf = cc;    time = predef::time(1);    if(f->sslfile)    f->sslfile->set_close_callback(end);    call_out(do_timeout, HTTPTIMEOUT);    }    root_id = this;   }      void chain( object f, object c, string le )   {    my_fd = f; -  +  + #ifdef DEBUG +  if (this_thread() != roxen->backend_thread) +  error ("Not called from backend\n"); + #endif +  +  CHECK_FD_SAFE_USE; +     f->set_nonblocking(0, f->query_write_callback(), end);    port_obj = c; -  processed = 0; -  do_not_disconnect=-1; // Block destruction until we return. +     MARK_FD("HTTP kept alive");    time = predef::time();    -  if ( le && sizeof( le ) ) -  got_data( 0,le ); +  if ( le && sizeof( le ) ) { + #ifdef CONNECTION_DEBUG +  werror("HTTP: Leftovers: %O\n", le); + #else +  REQUEST_WERR(sprintf("HTTP: %d bytes left over.\n", sizeof(le))); + #endif +  got_data( 0,le, 1); +  }    else    {    // If no pipelined data is available, call out...    remove_call_out(do_timeout);    call_out(do_timeout, HTTPTIMEOUT); -  +  my_fd->set_nonblocking(got_data, 0, close_cb);    } -  -  if(!my_fd) -  { -  if(do_not_disconnect == -1) -  { -  do_not_disconnect=0; -  disconnect(); +    } -  } -  else -  { -  if(do_not_disconnect == -1) -  do_not_disconnect = 0; -  f->set_nonblocking(!processed && got_data, f->query_write_callback(), end); -  } - } +     - string _sprintf(int t) - { -  if(t!='O') return 0; -  return "RequestID(" + (raw_url||"") + ")" - #ifdef ID_OBJ_DEBUG -  + (__marker ? "[" + __marker->count + "]" : "") - #endif -  ; - } -  +    Stdio.File connection( )   {    return my_fd;   }      Configuration configuration()   {    return conf;   }