2 /* -}{----------------------------------------------------------------------- */
7 #include <notification.h>
9 /* -}{---- ------------------------------------------------------------------ */
11 static k_hashtable* entity_headers;
13 /* -}{---- ------------------------------------------------------------------ */
15 #define TMPBUFSIZE 4096
16 static char tmpbuf[TMPBUFSIZE];
18 /* -}{----------------------------------------------------------------------- */
20 static char* get_request( char* header, k_hashtable*, k_hashtable*);
21 static char* get_response(char* header, k_hashtable*, k_hashtable*);
22 static char* get_val(char** atp);
23 static char* end_of_val(char* at);
24 static void fix_keepalive(k_hashtable* evt_head);
25 static void fix_cache_control(k_hashtable* ent_head);
26 static void fix_uri(k_hashtable* ent_head);
27 static void fix_subscribe(k_hashtable*, k_hashtable*);
29 /* -}{----------------------------------------------------------------------- */
31 #define WHITESPACEH " \t"
32 #define WHITESPACEV "\012\015"
33 #define WHITESPACE WHITESPACEH WHITESPACEV
35 EXPORT ni_event* ni_get_request_headers(char* header)
37 k_hashtable* evt_head=k_hashtable_new("vHeaders/get_req_hdrs", 1);
38 k_hashtable* ent_head=k_hashtable_new("nHeaders/get_req_hdrs", 1);
39 k_hashtable_put(ent_head, "", header);
41 char* h=get_request(header, evt_head, ent_head);
43 k_hashtable_delete(evt_head);
44 k_hashtable_delete(ent_head);
48 h=ni_get_headers(h, evt_head, ent_head);
50 k_hashtable_delete(evt_head);
51 k_hashtable_delete(ent_head);
55 fix_keepalive(evt_head);
56 fix_cache_control(ent_head);
58 fix_subscribe(evt_head, ent_head);
60 ni_event* evq=ni_event_new(0, evt_head, ent_head, 0);
65 EXPORT ni_event* ni_get_response_headers(char* header)
67 k_hashtable* evt_head=k_hashtable_new("vHeaders/get_resp_hdrs", 1);
68 k_hashtable* ent_head=k_hashtable_new("nHeaders/get_resp_hdrs", 1);
69 k_hashtable_put(ent_head, "", header);
71 char* h=get_response(header, evt_head, ent_head);
73 k_hashtable_delete(evt_head);
74 k_hashtable_delete(ent_head);
78 h=ni_get_headers(h, evt_head, ent_head);
80 k_hashtable_delete(evt_head);
81 k_hashtable_delete(ent_head);
85 ni_event* evt=ni_event_new(0, evt_head, ent_head, 0);
90 EXPORT char* ni_get_headers(char* header,
91 k_hashtable* evt_head,
92 k_hashtable* ent_head)
100 at=strpbrk(at, WHITESPACE);
101 if(!at || at==tag) return 0;
106 if(strlen(val) > 2048) return 0;
109 h=k_hashtable_get(entity_headers, tag)? ent_head: evt_head;
111 char* old=k_hashtable_get(h, tag);
112 if(!old) k_hashtable_set(h, tag, val);
118 EXPORT void ni_fix_http_headers(k_hashtable* ent_head)
120 if(k_hashtable_is(ent_head, "Status:", "260")){
121 char* crn=k_hashtable_get(ent_head, "Content-Range:");
122 char* clg=k_hashtable_get(ent_head, "Content-Length-Given:");
124 k_hashtable_set(ent_head, "Status:", "206");
125 k_hashtable_set(ent_head, "Status-Text:", "Partial Content");
128 k_hashtable_set(ent_head, "Status:", "200");
129 k_hashtable_set(ent_head, "Status-Text:", "OK");
132 k_hashtable_remove(ent_head, "URI:");
133 k_hashtable_remove(ent_head, "Method:");
134 k_hashtable_remove(ent_head, "From:");
135 k_hashtable_remove(ent_head, "Content-Length-Given:");
136 k_hashtable_remove(ent_head, "Last-Modified-Epoch:");
138 char* cc=k_hashtable_get(ent_head, "Cache-Control:");
139 if(cc && strstr(cc, "no-cache")){
140 k_hashtable_set(ent_head, "Pragma:", "no-cache");
144 EXPORT void ni_fix_ni_headers(k_hashtable* ent_head, int methead)
146 if(methead && (k_hashtable_is(ent_head, "Status:", "200") ||
147 k_hashtable_is(ent_head, "Status:", "206") )){
149 k_hashtable_set(ent_head, "Status:", "260");
150 k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
152 k_hashtable_remove(ent_head, "Method:");
153 k_hashtable_remove(ent_head, "Sub-To:");
154 k_hashtable_remove(ent_head, "Via:");
155 k_hashtable_set( ent_head, "From:", ni_hostname());
157 char* uri=k_hashtable_get(ent_head, "URI:");
159 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", ni_hostname(), uri+2);
160 k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
164 EXPORT void ni_response(ni_event* evt,
172 snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc_relative(0));
173 k_hashtable_put_dup(evt->evt_head, "Date:", tmpbuf);
174 k_hashtable_set( evt->evt_head, "Server:", k_version);
176 k_hashtable_put_dup(evt->evt_head, "Connection:", connection);
178 int status =k_hashtable_get_int(evt->ent_head, "Status:");
179 char* statustext=k_hashtable_get( evt->ent_head, "Status-Text:");
180 int datalength=k_hashtable_get_int(evt->ent_head, "Content-Length:");
181 int constant =k_hashtable_is( evt->ent_head, "CUX:", "C");
184 int bufsize=TMPBUFSIZE;
187 ln+=snprintf(buf+ln, bufsize-ln, "%s %d %s" CRLF,
188 protocol, status, statustext);
189 if(ln>=bufsize) return;
191 static char* exheaders[]={ "Status:", "Status-Text:",
192 "Protocol:", "CUX:", 0 };
194 ln+=k_hashtable_snprintf_x(evt->evt_head, buf+ln,bufsize-ln, exheaders);
195 if(ln>=bufsize) return;
197 ln+=k_hashtable_snprintf_x(evt->ent_head, buf+ln,bufsize-ln, exheaders);
198 if(ln>=bufsize) return;
200 ln+=snprintf(buf+ln, bufsize-ln, CRLF);
201 if(ln>=bufsize) return;
203 char* head=k_strdup(buf);
204 if(L) k_log_out("Actual response headers:\n%s", head);
205 k_channel_send(chan, head, ln, FREE_ON_SENT);
207 if(evt->entity && datalength){
208 k_channel_send(chan, evt->entity, datalength, !constant);
212 if(!constant) k_free(evt->entity);
214 k_log_out("%s %s %s %d %d", to, method, evt->uri, status, datalength);
217 EXPORT void ni_request(ni_event* evt, char* to, char* method, k_channel* chan)
219 k_hashtable* sub=evt->ent_head;
222 int bufsize=TMPBUFSIZE;
224 ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s //%s OP/0.5" CRLF, method, to);
225 if(ln>=bufsize) return;
227 ln+=k_hashtable_snprintf(sub, tmpbuf+ln, bufsize-ln);
228 if(ln>=bufsize) return;
230 ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
231 if(ln>=bufsize) return;
233 char* head=k_strdup(tmpbuf);
234 if(0) k_log_out("Actual request headers:\n%s", head);
235 k_channel_send(chan, head, ln, FREE_ON_SENT);
238 /* -}{----------------------------------------------------------------------- */
240 char* get_request(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
244 at=strpbrk(at, WHITESPACEH);
248 k_hashtable_set(ent_head, "Method:", method);
252 if(strcmp(method, "PING")){
254 at+=strspn(at, WHITESPACEH);
256 at=strpbrk(at, WHITESPACEH);
259 if(strlen(file) > 1024 ) return 0;
261 if(!strncmp(file, "http://", 7)){
263 if(!*s || *s=='/') return 0;
264 char* e=strchr(s, '/');
271 if(*file=='/') file++;
276 if(!*s || *s=='/') return 0;
277 char* e=strchr(s, '/');
284 if(file) k_hashtable_set(evt_head, "File:", file);
285 if(host) k_hashtable_set(evt_head, "Host:", host);
287 at+=strspn(at, WHITESPACEH);
289 at=strpbrk(at, WHITESPACE);
290 if(!at) at=protocol+strlen(protocol);
293 k_hashtable_set(evt_head, "Protocol:", protocol);
295 at+=strspn(at, WHITESPACE);
299 char* get_response(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
303 at=strpbrk(at, WHITESPACEH);
307 k_hashtable_set(evt_head, "Protocol:", protocol);
309 at+=strspn(at, WHITESPACEH);
311 at=strpbrk(at, WHITESPACEH);
315 at+=strspn(at, WHITESPACEH);
317 at=strpbrk(at, WHITESPACEV);
321 k_hashtable_set(ent_head, "Status:", status);
322 k_hashtable_set(ent_head, "Status-Text:", statustext);
324 at+=strspn(at, WHITESPACE);
328 char* get_val(char** atp)
333 val+=strspn(val, WHITESPACEH);
334 val+=strspn(val, WHITESPACEV);
336 char* eov=end_of_val(at);
340 *atp=eov+strspn(eov, WHITESPACEV);
344 char* end_of_val(char* at)
348 char* v=strpbrk(at, WHITESPACEV);
349 if(!v) return at+strlen(at);
351 at=v+strspn(v, WHITESPACEV);
353 }while(strspn(at, WHITESPACEH));
358 void fix_keepalive(k_hashtable* evt_head)
361 int is11=k_hashtable_is( evt_head, "Protocol:", "HTTP/1.1");
362 int isps=k_hashtable_isn(evt_head, "Protocol:", "OP/", 4);
363 int iska=k_hashtable_isi(evt_head, "Connection:", "Keep-Alive");
364 int iscl=k_hashtable_isi(evt_head, "Connection:", "close");
365 if((!is11 && iska) || (is11 && !iscl) || isps){
368 if(0) k_log_out("is11=%d iska=%d iscl=%d isps=%d ka=%d",
369 is11, iska, iscl, isps, keepalive);
370 k_hashtable_set(evt_head, "Connection:",
371 keepalive? "Keep-Alive": "close");
374 void fix_cache_control(k_hashtable* ent_head)
376 char* cachec=k_hashtable_get( ent_head, "Cache-Control:");
377 char* pragma=k_hashtable_extract(ent_head, "Pragma:");
378 if(!cachec && pragma && strstr(pragma, "no-cache")){
379 k_hashtable_set( ent_head, "Cache-Control:","no-cache");
383 void fix_uri(k_hashtable* ent_head)
385 char* uri=k_hashtable_get(ent_head, "URI:");
387 char* nihostname=ni_hostname();
388 int l=strlen(nihostname);
389 if(strncmp(uri, nihostname, l)) return;
390 snprintf(tmpbuf, TMPBUFSIZE, ".%s", uri+l);
391 k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
394 void fix_subscribe(k_hashtable* evt_head, k_hashtable* ent_head)
396 char* host=k_hashtable_extract(evt_head, "Host:");
397 char* file=k_hashtable_extract(evt_head, "File:");
399 k_string_url_decode(host);
400 int localhostdns=!strcmp( host, "localhost") ||
401 !strncmp(host, "localhost:", 10);
402 int localhostni=!strcmp(host, ni_hostname());
403 char* lastdot=strrchr(host, '.');
404 int dotdotnumber=lastdot && atoi(lastdot+1) >0;
405 if(localhostdns || localhostni || dotdotnumber){
413 k_string_url_decode(file);
414 snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", host, file);
415 k_hashtable_put_dup(ent_head, "Sub-To:", tmpbuf);
416 k_hashtable_set( ent_head, "Sub-Type:", "Original");
420 void init_headers(void)
422 entity_headers =k_hashtable_new("Entity Headers", 1);
424 k_hashtable_set(entity_headers, "URI:", (void*)1);
425 k_hashtable_set(entity_headers, "From:", (void*)1);
426 k_hashtable_set(entity_headers, "To:", (void*)1);
427 k_hashtable_set(entity_headers, "Via:", (void*)1);
428 k_hashtable_set(entity_headers, "Sub-To:", (void*)1);
429 k_hashtable_set(entity_headers, "Sub-Type:", (void*)1);
430 k_hashtable_set(entity_headers, "Method:", (void*)1);
431 k_hashtable_set(entity_headers, "Status:", (void*)1);
432 k_hashtable_set(entity_headers, "Status-Text:", (void*)1);
433 k_hashtable_set(entity_headers, "Last-Modified-Epoch:", (void*)1);
434 k_hashtable_set(entity_headers, "CUX:", (void*)1);
436 k_hashtable_set(entity_headers, "Range:", (void*)1);
437 k_hashtable_set(entity_headers, "If-Modified-Since:", (void*)1);
438 k_hashtable_set(entity_headers, "If-None-Match:", (void*)1);
439 k_hashtable_set(entity_headers, "Cache-Control:", (void*)1);
440 k_hashtable_set(entity_headers, "Pragma:", (void*)1);
442 k_hashtable_set(entity_headers, "Content-Length:", (void*)1);
443 k_hashtable_set(entity_headers, "Content-Type:", (void*)1);
444 k_hashtable_set(entity_headers, "Content-Encoding:", (void*)1);
445 k_hashtable_set(entity_headers, "Content-Location:", (void*)1);
446 k_hashtable_set(entity_headers, "Content-MD5:", (void*)1);
447 k_hashtable_set(entity_headers, "Content-Language:", (void*)1);
448 k_hashtable_set(entity_headers, "Content-Range:", (void*)1);
449 k_hashtable_set(entity_headers, "Last-Modified:", (void*)1);
450 k_hashtable_set(entity_headers, "ETag:", (void*)1);
451 k_hashtable_set(entity_headers, "Expires:", (void*)1);
453 k_hashtable_set(entity_headers, "Allow:", (void*)1);
456 void drop_entity_headers(k_hashtable* ent_head)
458 k_hashtable_remove(ent_head, "Content-Length:");
459 k_hashtable_remove(ent_head, "Content-Range:");
460 k_hashtable_remove(ent_head, "Content-Type:");
461 k_hashtable_remove(ent_head, "Content-Encoding:");
462 k_hashtable_remove(ent_head, "Content-Location:");
463 k_hashtable_remove(ent_head, "Last-Modified:");
464 #ifdef DO_THESE_ONES_TOO
465 k_hashtable_remove(ent_head, "Allow:");
466 k_hashtable_remove(ent_head, "Content-Language:");
467 k_hashtable_remove(ent_head, "Content-MD5:");
468 k_hashtable_remove(ent_head, "Expires:");
472 void fill_headers(k_hashtable* ent_head,
483 k_hashtable_put_dup(ent_head, "Status:", status);
484 k_hashtable_put_dup(ent_head, "Status-Text:", statustext);
487 k_hashtable_put_dup(ent_head, "URI:", uri);
490 snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc(modifitime));
491 k_hashtable_put_dup(ent_head, "Last-Modified:", tmpbuf);
494 snprintf(tmpbuf, TMPBUFSIZE, "%d", datalength);
495 k_hashtable_put_dup(ent_head, "Content-Length:", tmpbuf);
498 k_hashtable_put_dup(ent_head, "Content-Type:", mimetype);
501 k_hashtable_put_dup(ent_head, "Content-Encoding:", encoding);
504 k_hashtable_put_dup(ent_head, "Cache-Control:",
505 "no-cache,no-store");
509 long maxage=31449600;
510 snprintf(tmpbuf, TMPBUFSIZE, "max-age=%ld", maxage);
511 char* maxages=k_time_to_rfc_relative(maxage);
512 k_hashtable_put_dup(ent_head, "Cache-Control:", tmpbuf);
513 k_hashtable_put_dup(ent_head, "Expires:", maxages);
517 k_hashtable_remove(ent_head, "Cache-Control:");
518 k_hashtable_remove(ent_head, "Expires:");
522 /* -}{---- ------------------------------------------------------------------ */