X-Git-Url: http://git.maemo.org/git/?p=cilux;a=blobdiff_plain;f=src%2Fon%2Fheaders.c;fp=src%2Fon%2Fheaders.c;h=13fc3e09b627042576fc07bb06e2aaeb317adaaf;hp=0000000000000000000000000000000000000000;hb=633d206d652087e0b170535a6e7fd0b33c8dc816;hpb=f9280086a261a27b286001ea0fd419de750a57c2;ds=sidebyside diff --git a/src/on/headers.c b/src/on/headers.c new file mode 100644 index 0000000..13fc3e0 --- /dev/null +++ b/src/on/headers.c @@ -0,0 +1,523 @@ + +/* -}{----------------------------------------------------------------------- */ + +#include +#undef PUBLIC +#define PUBLIC EXPORT +#include + +/* -}{---- ------------------------------------------------------------------ */ + +static k_hashtable* entity_headers; + +/* -}{---- ------------------------------------------------------------------ */ + +#define TMPBUFSIZE 4096 +static char tmpbuf[TMPBUFSIZE]; + +/* -}{----------------------------------------------------------------------- */ + +static char* get_request( char* header, k_hashtable*, k_hashtable*); +static char* get_response(char* header, k_hashtable*, k_hashtable*); +static char* get_val(char** atp); +static char* end_of_val(char* at); +static void fix_keepalive(k_hashtable* evt_head); +static void fix_cache_control(k_hashtable* ent_head); +static void fix_uri(k_hashtable* ent_head); +static void fix_subscribe(k_hashtable*, k_hashtable*); + +/* -}{----------------------------------------------------------------------- */ + +#define WHITESPACEH " \t" +#define WHITESPACEV "\012\015" +#define WHITESPACE WHITESPACEH WHITESPACEV + +EXPORT ni_event* ni_get_request_headers(char* header) +{ + k_hashtable* evt_head=k_hashtable_new("vHeaders/get_req_hdrs", 1); + k_hashtable* ent_head=k_hashtable_new("nHeaders/get_req_hdrs", 1); + k_hashtable_put(ent_head, "", header); + + char* h=get_request(header, evt_head, ent_head); + if(!h){ + k_hashtable_delete(evt_head); + k_hashtable_delete(ent_head); + return 0; + } + + h=ni_get_headers(h, evt_head, ent_head); + if(!h){ + k_hashtable_delete(evt_head); + k_hashtable_delete(ent_head); + return 0; + } + + fix_keepalive(evt_head); + fix_cache_control(ent_head); + fix_uri(ent_head); + fix_subscribe(evt_head, ent_head); + + ni_event* evq=ni_event_new(0, evt_head, ent_head, 0); + + return evq; +} + +EXPORT ni_event* ni_get_response_headers(char* header) +{ + k_hashtable* evt_head=k_hashtable_new("vHeaders/get_resp_hdrs", 1); + k_hashtable* ent_head=k_hashtable_new("nHeaders/get_resp_hdrs", 1); + k_hashtable_put(ent_head, "", header); + + char* h=get_response(header, evt_head, ent_head); + if(!h){ + k_hashtable_delete(evt_head); + k_hashtable_delete(ent_head); + return 0; + } + + h=ni_get_headers(h, evt_head, ent_head); + if(!h){ + k_hashtable_delete(evt_head); + k_hashtable_delete(ent_head); + return 0; + } + + ni_event* evt=ni_event_new(0, evt_head, ent_head, 0); + + return evt; +} + +EXPORT char* ni_get_headers(char* header, + k_hashtable* evt_head, + k_hashtable* ent_head) +{ + char* at=header; + char* tag; + char* val; + while(*at){ + + tag=at; + at=strpbrk(at, WHITESPACE); + if(!at || at==tag) return 0; + char* e=at; + val=get_val(&at); + *e=0; + + if(strlen(val) > 2048) return 0; + + k_hashtable* h; + h=k_hashtable_get(entity_headers, tag)? ent_head: evt_head; + if(h){ + char* old=k_hashtable_get(h, tag); + if(!old) k_hashtable_set(h, tag, val); + } + } + return at; +} + +EXPORT void ni_fix_http_headers(k_hashtable* ent_head) +{ + if(k_hashtable_is(ent_head, "Status:", "260")){ + char* crn=k_hashtable_get(ent_head, "Content-Range:"); + char* clg=k_hashtable_get(ent_head, "Content-Length-Given:"); + if(crn || clg){ + k_hashtable_set(ent_head, "Status:", "206"); + k_hashtable_set(ent_head, "Status-Text:", "Partial Content"); + } + else{ + k_hashtable_set(ent_head, "Status:", "200"); + k_hashtable_set(ent_head, "Status-Text:", "OK"); + } + } + k_hashtable_remove(ent_head, "URI:"); + k_hashtable_remove(ent_head, "Method:"); + k_hashtable_remove(ent_head, "From:"); + k_hashtable_remove(ent_head, "Content-Length-Given:"); + k_hashtable_remove(ent_head, "Last-Modified-Epoch:"); + + char* cc=k_hashtable_get(ent_head, "Cache-Control:"); + if(cc && strstr(cc, "no-cache")){ + k_hashtable_set(ent_head, "Pragma:", "no-cache"); + } +} + +EXPORT void ni_fix_ni_headers(k_hashtable* ent_head, int methead) +{ + if(methead && (k_hashtable_is(ent_head, "Status:", "200") || + k_hashtable_is(ent_head, "Status:", "206") )){ + + k_hashtable_set(ent_head, "Status:", "260"); + k_hashtable_set(ent_head, "Status-Text:", "Headers Only"); + } + k_hashtable_remove(ent_head, "Method:"); + k_hashtable_remove(ent_head, "Sub-To:"); + k_hashtable_remove(ent_head, "Via:"); + k_hashtable_set( ent_head, "From:", ni_hostname()); + + char* uri=k_hashtable_get(ent_head, "URI:"); + if(*uri=='.'){ + snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", ni_hostname(), uri+2); + k_hashtable_put_dup(ent_head, "URI:", tmpbuf); + } +} + +EXPORT void ni_response(ni_event* evt, + char* to, + char* method, + char* protocol, + char* connection, + k_channel* chan) +{ + int L=0; + snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc_relative(0)); + k_hashtable_put_dup(evt->evt_head, "Date:", tmpbuf); + k_hashtable_set( evt->evt_head, "Server:", k_version); + if(connection) + k_hashtable_put_dup(evt->evt_head, "Connection:", connection); + + int status =k_hashtable_get_int(evt->ent_head, "Status:"); + char* statustext=k_hashtable_get( evt->ent_head, "Status-Text:"); + int datalength=k_hashtable_get_int(evt->ent_head, "Content-Length:"); + int constant =k_hashtable_is( evt->ent_head, "CUX:", "C"); + + char* buf =tmpbuf; + int bufsize=TMPBUFSIZE; + int ln=0; + + ln+=snprintf(buf+ln, bufsize-ln, "%s %d %s" CRLF, + protocol, status, statustext); + if(ln>=bufsize) return; + + static char* exheaders[]={ "Status:", "Status-Text:", + "Protocol:", "CUX:", 0 }; + + ln+=k_hashtable_snprintf_x(evt->evt_head, buf+ln,bufsize-ln, exheaders); + if(ln>=bufsize) return; + + ln+=k_hashtable_snprintf_x(evt->ent_head, buf+ln,bufsize-ln, exheaders); + if(ln>=bufsize) return; + + ln+=snprintf(buf+ln, bufsize-ln, CRLF); + if(ln>=bufsize) return; + + char* head=k_strdup(buf); + if(L) k_log_out("Actual response headers:\n%s", head); + k_channel_send(chan, head, ln, FREE_ON_SENT); + + if(evt->entity && datalength){ + k_channel_send(chan, evt->entity, datalength, !constant); + } + else{ + datalength=0; + if(!constant) k_free(evt->entity); + } + k_log_out("%s %s %s %d %d", to, method, evt->uri, status, datalength); +} + +EXPORT void ni_request(ni_event* evt, char* to, char* method, k_channel* chan) +{ + k_hashtable* sub=evt->ent_head; + + int ln=0; + int bufsize=TMPBUFSIZE; + + ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s //%s OP/0.5" CRLF, method, to); + if(ln>=bufsize) return; + + ln+=k_hashtable_snprintf(sub, tmpbuf+ln, bufsize-ln); + if(ln>=bufsize) return; + + ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF); + if(ln>=bufsize) return; + + char* head=k_strdup(tmpbuf); + if(0) k_log_out("Actual request headers:\n%s", head); + k_channel_send(chan, head, ln, FREE_ON_SENT); +} + +/* -}{----------------------------------------------------------------------- */ + +char* get_request(char* header, k_hashtable* evt_head, k_hashtable* ent_head) +{ + char* at=header; + char* method=at; + at=strpbrk(at, WHITESPACEH); + if(!at) return 0; + *at++=0; + + k_hashtable_set(ent_head, "Method:", method); + + char* file=0; + char* host=0; + if(strcmp(method, "PING")){ + + at+=strspn(at, WHITESPACEH); + file=at; + at=strpbrk(at, WHITESPACEH); + if(!at) return 0; + *at++=0; + if(strlen(file) > 1024 ) return 0; + + if(!strncmp(file, "http://", 7)){ + char* s=file+7; + if(!*s || *s=='/') return 0; + char* e=strchr(s, '/'); + if(!e) return 0; + host=s; + *e++=0; + file=e; + } + else + if(*file=='/') file++; + else return 0; + + if(*file=='/'){ + char* s=file+1; + if(!*s || *s=='/') return 0; + char* e=strchr(s, '/'); + if(!e) return 0; + host=s; + *e++=0; + file=e; + } + } + if(file) k_hashtable_set(evt_head, "File:", file); + if(host) k_hashtable_set(evt_head, "Host:", host); + + at+=strspn(at, WHITESPACEH); + char* protocol=at; + at=strpbrk(at, WHITESPACE); + if(!at) at=protocol+strlen(protocol); + else *at++=0; + + k_hashtable_set(evt_head, "Protocol:", protocol); + + at+=strspn(at, WHITESPACE); + return at; +} + +char* get_response(char* header, k_hashtable* evt_head, k_hashtable* ent_head) +{ + char* at=header; + char* protocol=at; + at=strpbrk(at, WHITESPACEH); + if(!at) return 0; + *at++=0; + + k_hashtable_set(evt_head, "Protocol:", protocol); + + at+=strspn(at, WHITESPACEH); + char* status=at; + at=strpbrk(at, WHITESPACEH); + if(!at) return 0; + *at++=0; + + at+=strspn(at, WHITESPACEH); + char* statustext=at; + at=strpbrk(at, WHITESPACEV); + if(!at) return 0; + *at++=0; + + k_hashtable_set(ent_head, "Status:", status); + k_hashtable_set(ent_head, "Status-Text:", statustext); + + at+=strspn(at, WHITESPACE); + return at; +} + +char* get_val(char** atp) +{ + char* at=*atp; + char* val=at; + + val+=strspn(val, WHITESPACEH); + val+=strspn(val, WHITESPACEV); + + char* eov=end_of_val(at); + if(eov0; + if(localhostdns || localhostni || dotdotnumber){ + host="."; + } + } + else{ + host="."; + } + if(file){ + k_string_url_decode(file); + snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", host, file); + k_hashtable_put_dup(ent_head, "Sub-To:", tmpbuf); + k_hashtable_set( ent_head, "Sub-Type:", "Original"); + } +} + +void init_headers(void) +{ + entity_headers =k_hashtable_new("Entity Headers", 1); + + k_hashtable_set(entity_headers, "URI:", (void*)1); + k_hashtable_set(entity_headers, "From:", (void*)1); + k_hashtable_set(entity_headers, "To:", (void*)1); + k_hashtable_set(entity_headers, "Via:", (void*)1); + k_hashtable_set(entity_headers, "Sub-To:", (void*)1); + k_hashtable_set(entity_headers, "Sub-Type:", (void*)1); + k_hashtable_set(entity_headers, "Method:", (void*)1); + k_hashtable_set(entity_headers, "Status:", (void*)1); + k_hashtable_set(entity_headers, "Status-Text:", (void*)1); + k_hashtable_set(entity_headers, "Last-Modified-Epoch:", (void*)1); + k_hashtable_set(entity_headers, "CUX:", (void*)1); + + k_hashtable_set(entity_headers, "Range:", (void*)1); + k_hashtable_set(entity_headers, "If-Modified-Since:", (void*)1); + k_hashtable_set(entity_headers, "If-None-Match:", (void*)1); + k_hashtable_set(entity_headers, "Cache-Control:", (void*)1); + k_hashtable_set(entity_headers, "Pragma:", (void*)1); + + k_hashtable_set(entity_headers, "Content-Length:", (void*)1); + k_hashtable_set(entity_headers, "Content-Type:", (void*)1); + k_hashtable_set(entity_headers, "Content-Encoding:", (void*)1); + k_hashtable_set(entity_headers, "Content-Location:", (void*)1); + k_hashtable_set(entity_headers, "Content-MD5:", (void*)1); + k_hashtable_set(entity_headers, "Content-Language:", (void*)1); + k_hashtable_set(entity_headers, "Content-Range:", (void*)1); + k_hashtable_set(entity_headers, "Last-Modified:", (void*)1); + k_hashtable_set(entity_headers, "ETag:", (void*)1); + k_hashtable_set(entity_headers, "Expires:", (void*)1); + + k_hashtable_set(entity_headers, "Allow:", (void*)1); +} + +void drop_entity_headers(k_hashtable* ent_head) +{ + k_hashtable_remove(ent_head, "Content-Length:"); + k_hashtable_remove(ent_head, "Content-Range:"); + k_hashtable_remove(ent_head, "Content-Type:"); + k_hashtable_remove(ent_head, "Content-Encoding:"); + k_hashtable_remove(ent_head, "Content-Location:"); + k_hashtable_remove(ent_head, "Last-Modified:"); +#ifdef DO_THESE_ONES_TOO + k_hashtable_remove(ent_head, "Allow:"); + k_hashtable_remove(ent_head, "Content-Language:"); + k_hashtable_remove(ent_head, "Content-MD5:"); + k_hashtable_remove(ent_head, "Expires:"); +#endif +} + +void fill_headers(k_hashtable* ent_head, + char* status, + char* statustext, + char* uri, + time_t modifitime, + int datalength, + char* mimetype, + char* encoding, + int nocache) +{ + if(status){ + k_hashtable_put_dup(ent_head, "Status:", status); + k_hashtable_put_dup(ent_head, "Status-Text:", statustext); + } + if(uri){ + k_hashtable_put_dup(ent_head, "URI:", uri); + } + if(modifitime>=0){ + snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc(modifitime)); + k_hashtable_put_dup(ent_head, "Last-Modified:", tmpbuf); + } + if(datalength>=0){ + snprintf(tmpbuf, TMPBUFSIZE, "%d", datalength); + k_hashtable_put_dup(ent_head, "Content-Length:", tmpbuf); + } + if(mimetype){ + k_hashtable_put_dup(ent_head, "Content-Type:", mimetype); + } + if(encoding){ + k_hashtable_put_dup(ent_head, "Content-Encoding:", encoding); + } + if(nocache==1){ + k_hashtable_put_dup(ent_head, "Cache-Control:", + "no-cache,no-store"); + } + else + if(nocache==0){ + long maxage=31449600; + snprintf(tmpbuf, TMPBUFSIZE, "max-age=%ld", maxage); + char* maxages=k_time_to_rfc_relative(maxage); + k_hashtable_put_dup(ent_head, "Cache-Control:", tmpbuf); + k_hashtable_put_dup(ent_head, "Expires:", maxages); + } + else + if(nocache== -1){ + k_hashtable_remove(ent_head, "Cache-Control:"); + k_hashtable_remove(ent_head, "Expires:"); + } +} + +/* -}{---- ------------------------------------------------------------------ */ +