Roxen.git/server/plugins/protocols/http.pike:1:
// This is a roxen protocol module.
// Modified by Francesco Chemolli to add throttling capabilities.
// Copyright © 1996 - 2001, Roxen IS.
- constant cvs_version = "$Id: http.pike,v 1.374 2002/07/03 12:56:00 nilsson Exp $";
+ constant cvs_version = "$Id: http.pike,v 1.375 2002/07/03 14:52:10 per Exp $";
// #define REQUEST_DEBUG
#define MAGIC_ERROR
#ifdef MAGIC_ERROR
inherit "highlight_pike";
#endif
// HTTP protocol module.
#include <config.h>
#define TIMER_PREFIX "http:"
Roxen.git/server/plugins/protocols/http.pike:93:
multiset (string) prestate = (< >);
multiset (string) config = (< >);
multiset (string) pragma = (< >);
mapping file;
string rest_query="";
string raw="";
string extra_extension = ""; // special hack for the language module
-
- static mapping connection_stats = ([]);
-
+
class AuthEmulator
// Emulate the old (rather cumbersome) authentication API
{
mixed `[]( int i )
{
User u;
switch( i )
{
case 0:
return conf->authenticate( this_object() );
Roxen.git/server/plugins/protocols/http.pike:324:
safe_decoder ) );
config = mkmultiset( map( (array(string))indices( config ),
safe_decoder ) );
pragma = mkmultiset( map( (array(string))indices( pragma ),
safe_decoder ) );
}
// 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.
- object pipe;
+ Shuffler.Shuffle pipe;
+ object throttler; // The inter-request throttling object.
- //used values: throttle->doit=0|1 to enable it
- // throttle->rate the rate
- // throttle->fixed if it's not to be touched again
- mapping(string:mixed) throttle = ([]);
-
- object throttler;//the inter-request throttling object.
-
- /* Pipe-using send functions */
-
- // FIXME:
- //I'm choosing the pipe type upon setup. Thus I'm assuming that all headers
- //have been defined before then. This is actually not true in case
- //of throttling and keep-alive. We'll take care of that later.
+
private void setup_pipe()
{
- if(!my_fd) {
+ if(!my_fd)
+ {
end();
return;
}
- if ( throttle->doit && conf->query("req_throttle") )
- throttle->doit = 0;
- if( throttle->doit || conf->throttler )
- pipe=roxen.slowpipe();
- else
- pipe=roxen.fastpipe();
- if (throttle->doit)
- {
- //we are sure that pipe is really a slowpipe.
- throttle->rate=max(throttle->rate, conf->query("req_throttle_min"));
- pipe->throttle(throttle->rate,
- (int)(throttle->rate*conf->query("req_throttle_depth_mult")),
- 0);
- THROTTLING_DEBUG("throtting request at "+throttle->rate);
+ pipe = roxen.get_shuffler( my_fd );
+ if( conf )
+ conf->connection_add( this_object(), pipe );
}
- if( pipe->set_status_mapping )
- pipe->set_status_mapping( connection_stats );
- if ( conf->throttler )
- pipe->assign_throttler( conf->throttler );
- }
+
- void send (string|object what, int|void len)
+ void send(string|object what, int|void len, int|void start)
{
- if( len>0 && port_obj && port_obj->minimum_byterate )
- call_out( end, len / port_obj->minimum_byterate );
-
+
if(!what) return;
if(!pipe) setup_pipe();
- if(stringp(what)) {
- REQUEST_WERR(sprintf("HTTP: Pipe string %O", what));
- pipe->write(what);
+ 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));
}
- else {
- REQUEST_WERR(sprintf("HTTP: Pipe stream %O, length %O", what, len));
- pipe->input(what,len);
- }
- }
+
void start_sender( )
{
- if (pipe)
- {
- MARK_FD("HTTP really handled, piping response");
+
#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->output( my_fd );
- } else {
- MARK_FD("HTTP really handled, pipe done");
- do_log();
+ pipe->start( );
}
- }
+
string scan_for_query( string f )
{
query=0;
rest_query="";
if(sscanf(f,"%s?%s", f, query) == 2)
{
string v, a, b;
foreach(query / "&", v)
Roxen.git/server/plugins/protocols/http.pike:1287:
#define INTERNAL_ERROR(err) \
if (mixed __eRr = catch (internal_error (err))) \
report_error("Internal server error: " + describe_backtrace(err) + \
"internal_error() also failed: " + describe_backtrace(__eRr))
int wants_more()
{
return !!cache;
}
- void do_log( int|void fsent )
+ void do_log( Shuffler.Shuffle r, int reason )
{
MARK_FD("HTTP logging"); // fd can be closed here
-
+ int fsent = r->sent_data();
+
TIMER_START(do_log);
if(conf)
{
- int len;
- if(!fsent && pipe)
- file->len = pipe->bytes_sent();
- else
- file->len = fsent;
- if(conf)
- {
- if(file->len > 0) conf->sent+=file->len;
+ conf->sent+=fsent;
file->len += misc->_log_cheat_addition;
conf->log(file, this_object());
}
- }
+
if( !port_obj )
{
TIMER_END(do_log);
MERGE_TIMERS(conf);
if( conf )
conf->connection_drop( this_object() );
catch // paranoia
{
my_fd->close();
destruct( my_fd );
Roxen.git/server/plugins/protocols/http.pike:1726:
if(ranges) // No incorrect syntax...
{
misc->cacheable = 0;
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->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];
+ file->start = ranges[0][0];
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.
file->file = MultiRangeWrapper(file, heads, ranges, this_object());
}
} else {
// Got the header, but the specified ranges was out of bounds.
// Reply with a 416 Requested Range not satisfiable.
Roxen.git/server/plugins/protocols/http.pike:1789:
error("Illegal value in headers array! "
"Expected string or array(string)\n");
head_string += "\r\n";
}
if( strlen( charset ) || String.width( head_string ) > 8 )
head_string = output_encode( head_string, 0, charset )[1];
conf->hsent += strlen(head_string);
}
}
- #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!=304) )
// No data for these two...
{
#ifdef RAM_CACHE
if( (misc->cacheable > 0) && (file->data || file->file) &&
prot != "HTTP/0.9" )
{
if( file->len>0 && // known length.
Roxen.git/server/plugins/protocols/http.pike:1830: Inside #if defined(RAM_CACHE)
"raw":file->raw,
"error":file->error,
"mtime":(file->stat && file->stat[ST_MTIME]),
"rf":realfile,
]),
misc->cacheable );
file = ([ "data":data, "raw":file->raw, "len":strlen(data) ]);
}
}
#endif
- if( file->len > 0 && file->len < 4000 )
- {
- // Just do a blocking write().
- int s;
- TIMER_END(send_result);
- TIMER_START(blocking_write);
- string data = head_string +
- (file->file?file->file->read(file->len):
- (file->data[..file->len-1]));
- REQUEST_WERR (sprintf ("HTTP: Send %O", data));
- s = my_fd->write(data);
- TIMER_END(blocking_write);
- do_log( s );
- return;
+ if(strlen(head_string))
+ send(head_string);
+ if(file->data && strlen(file->data))
+ send(file->data, file->len, file->start);
+ if(file->file)
+ send(file->file, file->len, file->start);
}
- 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);
- }
+
else
{
- if( strlen( head_string ) < 4000)
- {
- REQUEST_WERR (sprintf ("HTTP: Send %O", head_string));
- do_log( my_fd->write( head_string ) );
- return;
- }
+
send(head_string);
file->len = 1; // Keep those alive, please...
}
TIMER_END(send_result);
start_sender();
}
// Execute the request
void handle_request( )
Roxen.git/server/plugins/protocols/http.pike:2111:
/* Need to authenticate with the configuration */
misc->cacheable = 0;
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() );
}
}
-
- conf->connection_add( this_object(), connection_stats );
+ if( conf )
+ {
+ conf->connection_add( this_object(), ([]) );
conf->received += strlen(raw);
conf->requests++;
-
+ }
my_fd->set_close_callback(0);
my_fd->set_read_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 &&
Roxen.git/server/plugins/protocols/http.pike:2191: Inside #if defined(RAM_CACHE)
{
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;
- if( strlen( d ) < 4000 )
- {
+
TIMER_END(cache_lookup);
- do_log( my_fd->write( fix_date(file->hs)+d ) );
- }
- else
- {
- TIMER_END(cache_lookup);
+
send( fix_date(file->hs)+d );
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.
Roxen.git/server/plugins/protocols/http.pike:2316:
my_fd = f;
MARK_FD("HTTP connection");
if( c ) port_obj = c;
if( cc ) conf = cc;
time = predef::time(1);
call_out(do_timeout, 90);
}
root_id = this_object();
}
- void chain(object f, object c, string le)
+ void chain( object f, object c, string le )
{
my_fd = f;
f->set_read_callback(0);
f->set_close_callback(end);
port_obj = c;
processed = 0;
do_not_disconnect=-1; // Block destruction until we return.
MARK_FD("HTTP kept alive");
time = predef::time(1);
Roxen.git/server/plugins/protocols/http.pike:2350:
do_not_disconnect=0;
disconnect();
}
}
else
{
if(do_not_disconnect == -1)
do_not_disconnect = 0;
if(!processed)
{
- f->set_read_callback(got_data);
- f->set_close_callback(end);
+ my_fd->set_read_callback(got_data);
+ my_fd->set_close_callback(end);
}
}
}
string _sprintf( )
{
return "RequestID(" + (raw_url||"") + ")"
#ifdef ID_OBJ_DEBUG
+ (__marker ? "[" + __marker->count + "]" : "")
#endif