2000-08-12
2000-08-12 06:16:22 by Per Hedbor <ph@opera.com>
-
a3ebeab3ef876c12eca45f046abac7c4a48bf9a4
(562 lines)
(+303/-259)
[
Show
| Annotate
]
Branch: 5.2
Use optimized C-functions if available, also, the configuration object may now be passed to create. In that case no search is done using the requested URL
Rev: server/protocols/http.pike:1.237
2:
// Modified by Francesco Chemolli to add throttling capabilities.
// Copyright © 1996 - 2000, Roxen IS.
- constant cvs_version = "$Id: http.pike,v 1.236 2000/08/09 02:36:09 per Exp $";
-
+ constant cvs_version = "$Id: http.pike,v 1.237 2000/08/12 06:16:22 per Exp $";
+ // #define REQUEST_DEBUG
#define MAGIC_ERROR
-
+ #undef OLD_RXML_COMPAT
+
#ifdef MAGIC_ERROR
inherit "highlight_pike";
#endif
231:
void decode_charset_encoding( string|function(string:string) decoder )
{
if(stringp(decoder))
- decoder = Roxen._charset_decoder( Locale.Charset.decoder(decoder) )->decode;
+ decoder = Roxen._charset_decoder(Locale.Charset.decoder(decoder))->decode;
if( misc->request_charset_decoded )
return;
385:
return f;
}
-
+ #ifdef OLD_RXML_COMPAT
private int really_set_config(array mod_config)
{
string url, m;
454:
}
return 2;
}
+ #endif
private static mixed f, line;
private static int hstart;
527:
sorted=1;
}
}
+ #if constant(Roxen.HeaderParser)
+ static Roxen.HeaderParser hp = Roxen.HeaderParser();
+ #endif
int last;
- private int parse_got()
+ private int parse_got( string new_data )
{
multiset (string) sup;
-
+ #ifdef OLD_RXML_COMPAT
array mod_config;
- string a, b, s="", linename, contents;
+
int config_in_url;
-
+ #endif
+ string a, b, s="", linename, contents;
+ mapping header_mapping = ([]);
-
+ #if constant(Roxen.HeaderParser)
+ if( !method )
+ {
+ array res;
+ if( catch { res = hp->feed( new_data ); } )
+ return 1;
+ if( !res )
+ return 0; // Not enough data;
+ /* now in res:
+
+ leftovers/data
+
+ first line
+ headers
+ */
+ data = res[0];
+ line = res[1];
+ header_mapping = res[2];
+ }
+ #else
REQUEST_WERR(sprintf("HTTP: parse_got(%O)", raw));
if (!method) { // Haven't parsed the first line yet.
int start;
579:
REQUEST_WERR(sprintf("HTTP: parse_got(%O): Malformed request.", raw));
return 1;
}
-
+ #endif
string trailer, trailer_trailer;
-
+
switch(sscanf(line+" ", "%s %s %s %s %s",
method, f, clientprot, trailer, trailer_trailer))
{
652:
// Too many or too few entries -> Hum.
return 1;
}
- } else {
+ #if !constant(Roxen.HeaderParser)
+ }
+ else
+ {
// HTTP/1.0 or later
// Check that the request is complete
int end;
666:
data = raw[end+4..];
s = raw[sizeof(line)+2..end-1];
}
+ #endif
if(method == "PING") {
my_fd->write("PONG\r\n");
return 2;
}
REQUEST_WERR(sprintf("***** req line: %O", line));
- REQUEST_WERR(sprintf("***** headers: %O", data));
+ REQUEST_WERR(sprintf("***** headers: %O", s));
REQUEST_WERR(sprintf("***** data: %O", data));
raw_url = f;
time = _time(1);
700:
f = http_decode_string( f );
string prf = f[1..1];
+ #ifdef OLD_RXML_COMPAT
if (prf == "<" && sscanf(f, "/<%s>/%s", a, f)==2)
{
config_in_url = 1;
mod_config = (a/",");
f = "/"+f;
}
-
+ #endif
REQUEST_WERR(sprintf("After cookie scan:%O", f));
725:
misc->pref_languages=PrefLanguages();
+ #if constant(Roxen.HeaderParser)
+ foreach( (array)header_mapping, [string linename,contents] )
+ #else
if(sizeof(s)) {
// sscanf(s, "%s\r\n\r\n%s", s, data);
// s = replace(s, "\n\t", ", ") - "\r";
735:
// linename=contents=0;
if(sscanf(line, "%s:%*[ \t]%s", linename, contents) == 3)
+ #endif
{
REQUEST_WERR(sprintf("Header-sscanf :%s", linename));
-
+ #if !constant(Roxen.HeaderParser)
linename=lower_case(linename);
REQUEST_WERR(sprintf("lower-case :%s", linename));
-
+ #endif
- // FIXME: Multiple headers?
+
request_headers[linename] = contents;
- if(strlen(contents))
+ if( arrayp( contents ) ) contents *= ", ";
+ switch (linename)
{
- switch (linename) {
+
case "content-length":
misc->len = (int)contents;
break;
847:
value=http_decode_string(value);
name=http_decode_string(name);
cookies[ name ]=value;
+ #ifdef OLD_RXML_CONFIG
if(name == "RoxenConfig" && strlen(value))
{
array tmpconfig = value/"," + ({ });
863:
mod_config = 0;
config = aggregate_multiset(@tmpconfig);
}
+ #endif
}
}
break;
889:
break;
}
}
+ #if !constant(Roxen.HeaderParser)
}
- }
+ #endif
if(misc->len && method == "POST")
{
if(!data) data="";
949:
break;
}
}
+ #if !constant(Roxen.HeaderParser)
}
-
+ #endif
REQUEST_WERR("HTTP: parse_got(): after header scan");
#ifndef DISABLE_SUPPORTS
if(!client) {
988:
}
raw = tmp2 * "\n";
}
+ #ifdef OLD_RXML_COMPAT
if(config_in_url) {
REQUEST_WERR("HTTP: parse_got(): config_in_url");
return really_set_config( mod_config );
}
-
+ #endif
if(!supports->cookies)
config = prestate;
else
1049: Inside #if defined(KEEP_ALIVE)
&& my_fd)
{
// Now.. Transfer control to a new http-object. Reset all variables etc..
- object o = object_program(this_object())(my_fd, port_obj);
+ object o = object_program(this_object())(my_fd, port_obj, conf);
o->remoteaddr = remoteaddr;
o->supports = supports;
o->host = host;
1627:
if(!file->raw)
{
heads = ([]);
- if(!file->len)
+ if( !file->len )
{
if(objectp(file->file))
if(!file->stat && !(file->stat=misc->stat))
1642:
misc->last_modified = fstat[3];
}
- if(prot != "HTTP/0.9") {
+ if(prot != "HTTP/0.9" && !misc->is_dynamic)
+ {
heads["Last-Modified"] = Roxen.http_date(misc->last_modified);
if(since)
{
/* ({ time, len }) */
- array(int) since_info = Roxen.parse_since(since);
+ array(int) since_info = Roxen.parse_since( since );
if ( ((since_info[0] >= misc->last_modified) &&
((since_info[1] == -1) || (since_info[1] == file->len)))
// actually ok, or...
1665:
}
}
}
- if(prot != "HTTP/0.9") {
+ if(prot != "HTTP/0.9")
+ {
string h, charset="";
if( stringp(file->data) )
1681:
if(stringp(file->data))
file->len = strlen(file->data);
}
+ heads["Content-type"] = file["type"]+charset;
+ heads["Accept-Ranges"] = "bytes";
+ heads["Server"] = replace(version(), " ", "·");
+ heads["Connection"] = (misc->connection=="close" ? "close": "keep-alive");
+ // heads["Date"] = Roxen.http_date(time),
- heads |= ([
- "MIME-Version" : (file["mime-version"] || "1.0"),
- "Content-type" : file["type"]+charset,
- "Accept-Ranges" : "bytes",
- "Server" : replace(version(), " ", "·"),
- #ifdef KEEP_ALIVE
- "Connection": (misc->connection == "close" ? "close": "Keep-Alive"),
- #else
- "Connection" : "close",
- #endif
- "Date" : Roxen.http_date(time)
- ]);
-
-
+
if(file->encoding)
heads["Content-Encoding"] = file->encoding;
1758:
}
}
}
-
+
head_string = prot+" "+(file->rettext||errors[file->error])+"\r\n";
-
+ if( file->len > 0 ) heads["Content-Length"] = (string)file->len;
+ if( file->len <= 0 ) misc->connection = "close";
+ #if constant( Roxen.make_http_headers )
+ head_string += Roxen.make_http_headers( heads );
+ #else
foreach(indices(heads), h)
if(arrayp(heads[h]))
foreach(heads[h], tmp)
head_string += h+": "+tmp+"\r\n";
else
head_string += h+": "+heads[h]+"\r\n";
-
- if(file->len > -1) {
- head_string += "Content-Length: "+ file->len +"\r\n";
- if (file->len == 0)
- // Some browsers, e.g. Netscape 4.7, doesn't trust a zero
- // content length when using keep-alive. So let's force a
- // close in that case.
- misc->connection = "close";
- }
- else
- misc->connection = "close";
-
+
head_string += "\r\n";
-
+ #endif
if(conf) conf->hsent += strlen(head_string);
}
}
1797:
// No data for these two...
{
if(my_fd->query_fd && my_fd->query_fd() >= 0 &&
- file->len > 0 && file->len < 2000)
+ file->len > 0 && file->len < 4000)
{
// Ordinary connection, and a short file.
// Just do a blocking write().
- my_fd->write(head_string+
- (file->file?file->file->read(file->len):
- (file->data[..file->len-1])));
+ my_fd->write(head_string);
+ my_fd->write(file->file?file->file->read(file->len):
+ (file->data[..file->len-1]));
do_log();
return;
}
1876:
array e;
if(e= catch(file = conf->handle_request( this_object() )))
INTERNAL_ERROR( e );
- if( !file || !file->pipe )
+
+ if( !file )
+ INTERNAL_ERROR(({"No data returned from handle_request\n",backtrace()}));
+ else if( file->try_again_later )
+ {
+ call_out( handle_request, file->try_again_later );
+ return;
+ }
+ if( !file->pipe )
send_result();
}
1915:
// If the request starts with newlines, it's a broken request. Really!
// sscanf(s, "%*[\n\r]%s", s);
- if(strlen(raw)) tmp = parse_got();
+ if(strlen(raw)) tmp = parse_got( s );
switch(tmp)
{
case 0:
1941:
if( input_charset )
decode_charset_encoding( input_charset );
+ if( !conf )
+ {
if (misc->host)
{
// FIXME: port_obj->name & port_obj->default_port are constant
1957:
{
// No host header.
// Fallback to using the first configuration bound to this port.
- conf = port_obj->urls[port_obj->sorted_urls[0]]->conf;
+ conf = port_obj->mu ||
+ (port_obj->mu = port_obj->urls[port_obj->sorted_urls[0]]->conf);
misc->defaulted = 1;
// Support delayed loading in this case too.
if (!conf->inited) {
conf->enable_all_modules();
}
}
-
+ }
if (rawauth)
{
2002:
my_fd->set_close_callback(0);
my_fd->set_read_callback(0);
processed=1;
- roxen.handle(this_object()->handle_request);
+ roxen.handle(handle_request);
})
{
2019:
object clone_me()
{
object c,t;
- c=object_program(t=this_object())(0, port_obj);
+ c=object_program(t=this_object())(0, port_obj, conf);
#ifdef ID_OBJ_DEBUG
werror ("clone %O -> %O\n", t, c);
#endif
2074:
end();
}
- static void create(object f, object c)
+ static void create(object f, object c, object cc)
{
if(f)
{
MARK_FD("HTTP connection");
f->set_nonblocking(got_data, 0, end);
my_fd = f;
- if( c )
- port_obj = c;
+ if( c ) port_obj = c;
+ if( cc ) conf = cc;
call_out(do_timeout, 30);
time = _time(1);
}