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.393 2003/01/23 16:21:02 mani Exp $";
+ constant cvs_version = "$Id: http.pike,v 1.394 2004/04/04 00:13:11 mani Exp $";
// #define REQUEST_DEBUG
#define MAGIC_ERROR
// HTTP protocol module.
#include <config.h>
#define TIMER_PREFIX "http:"
#include <timers.h>
inherit RequestID;
Roxen.git/server/plugins/protocols/http.pike:48:
#define THROTTLING_DEBUG(X)
#endif
constant decode = MIME.decode_base64;
constant find_supports_and_vars = core.find_supports_and_vars;
constant version = core.version;
constant _query = core.query;
private static array(string) cache;
private static int wanted_data, have_data;
+ private static String.Buffer data_buffer;
#include <roxen.h>
#include <module.h>
#include <variables.h>
#include <request_trace.h>
#define MY_TRACE_ENTER(A, B) \
do {RequestID id = this_object(); TRACE_ENTER (A, B);} while (0)
#define MY_TRACE_LEAVE(A) \
do {RequestID id = this_object(); TRACE_LEAVE (A);} while (0)
mapping(string:array) real_variables = ([]);
mapping(string:mixed)|FakedVariables variables = FakedVariables( real_variables );
mapping (string:mixed) misc =
([
- #if 0
+
#ifdef REQUEST_DEBUG
"trace_enter":lambda(mixed ...args) {
REQUEST_WERR(sprintf("TRACE_ENTER(%{%O,%})", args));
},
"trace_leave":lambda(mixed ...args) {
REQUEST_WERR(sprintf("TRACE_LEAVE(%{%O,%})", args));
}
#endif // REQUEST_DEBUG
- #endif
+
]);
mapping (string:string) cookies = ([ ]);
mapping (string:string) request_headers = ([ ]);
mapping (string:string) client_var = ([ ]);
multiset (string) prestate = (< >);
multiset (string) config = (< >);
multiset (string) pragma = (< >);
mapping file;
Roxen.git/server/plugins/protocols/http.pike:324:
void start_sender( )
{
#ifdef FD_DEBUG
call_out(timer, 30, predef::time(1)); // Update FD with time...
#endif
if( throttler || conf->throttler )
pipe->set_throttler( throttler || conf->throttler );
pipe->set_done_callback( do_log );
pipe->start( );
+ data_buffer = 0;
pipe = 0;
}
string scan_for_query( string f )
{
query=0;
rest_query="";
if(sscanf(f,"%s?%s", f, query) == 2)
{
string v, a, b;
Roxen.git/server/plugins/protocols/http.pike:541: Inside #if undefined(DISABLE_SUPPORTS)
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" )
{
- misc->cacheable = 0;
+ misc->no_proto_cache = 1;
set_output_charset( client_var->charset );
input_charset = client_var->charset;
decode_charset_encoding( client_var->charset );
}
#else
supports = (< "images", "gifinline", "forms", "mailto">);
#endif
//REQUEST_WERR("HTTP: parse_got(): supports");
if(!referer) referer = ({ });
if(misc->proxyauth)
Roxen.git/server/plugins/protocols/http.pike:658:
clientprot = prot = "HTTP/0.9";
if(method != "PING")
method = "GET"; // 0.9 only supports get.
else
{
my_fd->write("PONG\r\n");
return 2;
}
s = data = ""; // no headers or extra data...
sscanf( f, "%s%*[\r\n]", f );
- misc->cacheable = 0;
+ misc->no_proto_cache = 1;
break;
case 0:
/* Not reached */
break;
}
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));
raw_url = f;
Roxen.git/server/plugins/protocols/http.pike:1104:
}
array get_error(string eid)
{
return cache_lookup( "http_bt_error", (int)eid );
}
void internal_error(array _err)
{
- misc->cacheable = 0;
+ misc->no_proto_cache = 1;
mixed err = _err;
_err = 0; // hide in backtrace, they are bad enough anyway...
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" +
Roxen.git/server/plugins/protocols/http.pike:1431:
#endif
;
array p;
if(!(p=conf->profile_map[nid]))
p = conf->profile_map[nid] = ({0,0.0,0.0});
p[0]++;
p[1] += elapsed;
if(elapsed > p[2]) p[2]=elapsed;
#endif
- REQUEST_WERR(sprintf("HTTP: response: prot %O, method %O, file %O",
- prot, method, file));
+ REQUEST_WERR(sprintf("HTTP: response: prot %O, method %O, file %O, misc: %O",
+ prot, method, file, misc));
-
+ if( prot == "HTTP/0.9" ) misc->no_proto_cache = 1;
+
if(!leftovers)
leftovers = data||"";
if(!mappingp(file))
{
- misc->cacheable = 0;
+ misc->no_proto_cache = 1;
if(misc->error_code)
file = Roxen.http_low_answer(misc->error_code, errors[misc->error]);
else if(err = catch {
file = conf->error_file( this_object() );
})
INTERNAL_ERROR(err);
}
else
{
if((file->file == -1) || file->leave_me)
Roxen.git/server/plugins/protocols/http.pike:1486:
if( Stat fstat = file->stat )
{
if( !file->len )
file->len = fstat[1];
if ( fstat[ST_MTIME] > misc->last_modified )
misc->last_modified = fstat[ST_MTIME];
}
- if( misc->cacheable < INITIAL_CACHEABLE ) {
+ if( !zero_type(misc->cacheable) &&
+ misc->cacheable < INITIAL_CACHEABLE ) {
if (misc->cacheable == 0) {
heads["Expires"] = Roxen.http_date( 0 );
if (!misc->last_modified) {
// Data with immediate expiry is assumed to have been generated
// at the same instant.
misc->last_modified = predef::time(1);
}
}
else
Roxen.git/server/plugins/protocols/http.pike:1511:
heads["Last-Modified"] = Roxen.http_date(misc->last_modified);
if(since && (!file->error || file->error == 200) && misc->last_modified)
{
// ({ time, len })
array(int) since_info = Roxen.parse_since( since );
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.
- && (misc->cacheable >= INITIAL_CACHEABLE) )
+ && (zero_type(misc->cacheable) ||
+ misc->cacheable >= INITIAL_CACHEABLE) )
{
file->error = 304;
file->file = 0;
file->data="";
}
}
if(prot != "HTTP/0.9")
{
string h, charset="";
Roxen.git/server/plugins/protocols/http.pike:1569:
// 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...
{
- misc->cacheable = 0;
+ misc->no_proto_cache = 1;
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);
file->start = ranges[0][0];
file->len = ranges[0][1] - ranges[0][0]+1;
} else {
Roxen.git/server/plugins/protocols/http.pike:1803:
* =================================================
*/
int processed;
// array ccd = ({});
void got_data(mixed fooid, string s)
{
REQUEST_WERR(sprintf("HTTP: Got %O", s));
if(wanted_data)
{
- data += s;
+
if(strlen(s) + have_data < wanted_data)
{
-
+ 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 += strlen(s);
-
+
// Reset timeout.
remove_call_out(do_timeout);
call_out(do_timeout, 90);
REQUEST_WERR("HTTP: We want more data.");
return;
}
-
+ if(data_buffer) {
+ data_buffer->add(s);
+ data = (string)data_buffer;
+ data_buffer = 0;
}
-
+ else
+ data += s;
+ }
if (mixed err = catch {
MARK_FD("HTTP got data");
raw += s;
// The port has been closed, but old (probably keep-alive)
// connections remain. Close those connections.
if( !port_obj )
{
if( conf )
Roxen.git/server/plugins/protocols/http.pike:1856:
"\r\n");
end();
return; // Stupid request.
case 2:
REQUEST_WERR("HTTP: Done.");
end();
return;
}
- if( method == "GET" )
+ if( (< "GET", "HEAD" >)[method] )
misc->cacheable = INITIAL_CACHEABLE; // FIXME: Make configurable.
TIMER_START(find_conf);
string path;
if( !conf || !(path = port_obj->path )
|| (sizeof( path )
&& raw_url[..sizeof(path) - 1] != path) )
{
// FIXME: port_obj->name & port_obj->default_port are constant
Roxen.git/server/plugins/protocols/http.pike:1910:
}
}
else if( strlen(path) )
adjust_for_config_path( path );
TIMER_END(find_conf);
if (rawauth)
{
/* Need to authenticate with the configuration */
- misc->cacheable = 0;
+ misc->no_proto_cache = 1;
array(string) y = rawauth / " ";
realauth = 0;
auth = 0;
if (sizeof(y) >= 2)
{
y[1] = MIME.decode_base64(y[1]);
realauth = y[1];
}
}
if( misc->proxyauth )
{
/* Need to authenticate with the configuration */
- misc->cacheable = 0;
+ misc->no_proto_cache = 1;
if (sizeof(misc->proxyauth) >= 2)
{
// misc->proxyauth[1] = MIME.decode_base64(misc->proxyauth[1]);
if (conf->auth_module)
misc->proxyauth
= conf->auth_module->auth(misc->proxyauth,this_object() );
}
}
if( conf )
{
Roxen.git/server/plugins/protocols/http.pike:2028: Inside #if defined(RAM_CACHE)
start_sender( );
return;
}
#ifndef RAM_CACHE_ASUME_STATIC_CONTENT
else
MY_TRACE_LEAVE (
sprintf ("Entry out of date (disk: %s, cache: mtime %d)",
st ? "mtime " + st->mtime : "gone", file->mtime));
#endif
} else
- misc->cacheable = 0; // Never cache in this case.
+ misc->no_proto_cache = 1; // Never cache in this case.
file = 0;
}
}
TIMER_END(cache_lookup);
#endif // RAM_CACHE
TIMER_START(parse_request);
if( things_to_do_when_not_sending_from_cache( ) )
return;
TIMER_END(parse_request);