From 5685e790de93f77083ea240f474a4870b194c550 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Wilfried=20G=C3=B6esgens?= Date: Sun, 27 Jul 2008 21:38:24 +0000 Subject: [PATCH] * use strbuffer as wprintf backend * modify all HTTP Headrs to be sent with hprintf() instead of wprintf() * end_burst now handles committing the headers and the buffer to the browser * use strbuf to keep static images --- webcit/autocompletion.c | 2 +- webcit/availability.c | 9 +- webcit/calendar.c | 15 +- webcit/context_loop.c | 3 + webcit/crypto.c | 2 +- webcit/downloads.c | 11 +- webcit/floors.c | 68 ++++----- webcit/groupdav_delete.c | 20 +-- webcit/groupdav_get.c | 60 ++++---- webcit/groupdav_main.c | 20 +-- webcit/groupdav_propfind.c | 44 +++--- webcit/groupdav_put.c | 80 +++++------ webcit/html2html.c | 2 +- webcit/messages.c | 8 +- webcit/paging.c | 6 +- webcit/rss.c | 31 ++-- webcit/serv_func.c | 95 +++++++------ webcit/siteconfig.c | 21 +-- webcit/tcp_sockets.c | 20 ++- webcit/webcit.c | 216 ++++++++++++++-------------- webcit/webcit.h | 18 +-- webcit/webserver.c | 283 ++++++++++++++----------------------- webcit/webserver.h | 1 - 23 files changed, 493 insertions(+), 542 deletions(-) diff --git a/webcit/autocompletion.c b/webcit/autocompletion.c index 69564e812..4cf4ccd6f 100644 --- a/webcit/autocompletion.c +++ b/webcit/autocompletion.c @@ -15,7 +15,7 @@ void recp_autocomplete(char *partial) { output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-type: text/html\r\n" + hprintf("Content-type: text/html\r\n" "Server: %s\r\n" "Connection: close\r\n" "Pragma: no-cache\r\n" diff --git a/webcit/availability.c b/webcit/availability.c index f2b4cdbe7..097725523 100644 --- a/webcit/availability.c +++ b/webcit/availability.c @@ -11,22 +11,23 @@ * Utility function to fetch a VFREEBUSY type of thing for any specified user. */ icalcomponent *get_freebusy_for_user(char *who) { + long nLines; char buf[SIZ]; - char *serialized_fb = NULL; + StrBuf *serialized_fb = NULL; icalcomponent *fb = NULL; serv_printf("ICAL freebusy|%s", who); serv_getln(buf, sizeof buf); if (buf[0] == '1') { - serialized_fb = read_server_text(); + serialized_fb = read_server_text(&nLines); } if (serialized_fb == NULL) { return NULL; } - fb = icalcomponent_new_from_string(serialized_fb); - free(serialized_fb); + fb = icalcomponent_new_from_string(ChrPtr(serialized_fb)); + FreeStrBuf(&serialized_fb); if (fb == NULL) { return NULL; } diff --git a/webcit/calendar.c b/webcit/calendar.c index 32a3e02f5..61d621993 100644 --- a/webcit/calendar.c +++ b/webcit/calendar.c @@ -1073,8 +1073,9 @@ void save_event(void) { void do_freebusy(char *req) { char who[SIZ]; char buf[SIZ]; - char *fb; + StrBuf *fb; int len; + long lines; extract_token(who, req, 1, ' ', sizeof who); if (!strncasecmp(who, "/freebusy/", 10)) { @@ -1094,17 +1095,17 @@ void do_freebusy(char *req) { serv_getln(buf, sizeof buf); if (buf[0] != '1') { - wprintf("HTTP/1.1 404 %s\n", &buf[4]); + hprintf("HTTP/1.1 404 %s\n", &buf[4]); output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("Content-Type: text/plain\r\n"); wprintf("%s\n", &buf[4]); + end_burst(); return; } - fb = read_server_text(); - http_transmit_thing(fb, strlen(fb), "text/calendar", 0); - free(fb); + fb = read_server_text(&lines); + http_transmit_thing(fb, "text/calendar", 0); + FreeStrBuf(&fb); } diff --git a/webcit/context_loop.c b/webcit/context_loop.c index 27e643093..4e10f92b2 100644 --- a/webcit/context_loop.c +++ b/webcit/context_loop.c @@ -102,6 +102,9 @@ void do_housekeeping(void) free_march_list(sessions_to_kill); DeleteHash(&(sessions_to_kill->hash_prefs)); DeleteHash(&(sessions_to_kill->IconBarSetttings)); + FreeStrBuf(&(sessions_to_kill->UrlFragment1)); + FreeStrBuf(&(sessions_to_kill->UrlFragment2)); + FreeStrBuf(&(sessions_to_kill->WBuf)); pthread_mutex_unlock(&sessions_to_kill->SessionMutex); sptr = sessions_to_kill->next; diff --git a/webcit/crypto.c b/webcit/crypto.c index bfb84cb5d..7db64940e 100644 --- a/webcit/crypto.c +++ b/webcit/crypto.c @@ -439,7 +439,7 @@ void ssl_lock(int mode, int n, const char *file, int line) * \param buf chars to send to the client * \param nbytes how many chars */ -void client_write_ssl(char *buf, int nbytes) +void client_write_ssl(const char *buf, int nbytes) { int retval; int nremain; diff --git a/webcit/downloads.c b/webcit/downloads.c index f2653746a..600d89de0 100644 --- a/webcit/downloads.c +++ b/webcit/downloads.c @@ -383,6 +383,7 @@ void display_mime_icon(void) void download_file(void) { + StrBuf *Buf; char buf[256]; off_t bytes; char content_type[256]; @@ -405,17 +406,17 @@ void download_file(void) extract_token(content_type, &buf[4], 3, '|', sizeof content_type); } output_headers(0, 0, 0, 0, 0, 0); - read_server_binary(content, bytes); + Buf = read_server_binary(bytes); serv_puts("CLOS"); serv_getln(buf, sizeof buf); - http_transmit_thing(content, bytes, content_type, 0); + http_transmit_thing(Buf, content_type, 0); free(content); } else { - wprintf("HTTP/1.1 404 %s\n", &buf[4]); + hprintf("HTTP/1.1 404 %s\n", &buf[4]); output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("Content-Type: text/plain\r\n"); wprintf(_("An error occurred while retrieving this file: %s\n"), &buf[4]); + end_burst(); } } diff --git a/webcit/floors.c b/webcit/floors.c index b5ee4028e..1b52c9aec 100644 --- a/webcit/floors.c +++ b/webcit/floors.c @@ -19,7 +19,7 @@ * will be displayed at the top of the screen. * \param prepend_html pagetitle to prepend */ -void display_floorconfig(char *prepend_html) +void display_floorconfig(StrBuf *prepend_html) { char buf[SIZ]; @@ -38,7 +38,7 @@ void display_floorconfig(char *prepend_html) if (prepend_html != NULL) { wprintf("
"); - client_write(prepend_html, strlen(prepend_html)); + StrBufAppendBuf(WC->WBuf, prepend_html, 0); wprintf("

\n"); } @@ -136,64 +136,66 @@ void display_floorconfig(char *prepend_html) */ void delete_floor(void) { int floornum; - char buf[SIZ]; - char message[SIZ]; - + StrBuf *Buf; + const char *Err; + floornum = ibstr("floornum"); - + Buf = NewStrBuf(); serv_printf("KFLR %d|1", floornum); - serv_getln(buf, sizeof buf); + + StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err); - if (buf[0] == '2') { - sprintf(message, _("Floor has been deleted.")); + if (ChrPtr(Buf)[0] == '2') { + StrBufPlain(Buf, _("Floor has been deleted."),-1); } else { - sprintf(message, "%s", &buf[4]); + StrBufCutLeft(Buf, 4); } - display_floorconfig(message); + display_floorconfig(Buf); + FreeStrBuf(&Buf); } /** * \brief tart creating a new floor */ void create_floor(void) { - char buf[SIZ]; - char message[SIZ]; - char floorname[SIZ]; + StrBuf *Buf; + const char *Err; - strcpy(floorname, bstr("floorname")); - - serv_printf("CFLR %s|1", floorname); - serv_getln(buf, sizeof buf); + Buf = NewStrBuf(); + serv_printf("CFLR %s|1", bstr("floorname")); + StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err); - if (buf[0] == '2') { - sprintf(message, _("New floor has been created.")); - } else { - sprintf(message, "%s", &buf[4]); + if (ChrPtr(Buf)[0] == '2') { + StrBufPlain(Buf, _("New floor has been created."),-1); + } + else { + StrBufCutLeft(Buf, 4); } - display_floorconfig(message); + display_floorconfig(Buf); + FreeStrBuf(&Buf); } + /** * \brief rename this floor */ void rename_floor(void) { - int floornum; - char buf[SIZ]; - char message[SIZ]; - char floorname[SIZ]; + StrBuf *Buf; - floornum = ibstr("floornum"); - strcpy(floorname, bstr("floorname")); + Buf = NewStrBuf(); - serv_printf("EFLR %d|%s", floornum, floorname); - serv_getln(buf, sizeof buf); + serv_printf("EFLR %d|%s", + ibstr("floornum"), + bstr("floorname")); + StrBuf_ServGetln(Buf); - sprintf(message, "%s", &buf[4]); + StrBufCutLeft(Buf, 4); - display_floorconfig(message); + display_floorconfig(Buf); + FreeStrBuf(&Buf); } void _display_floorconfig(void) {display_floorconfig(NULL);} diff --git a/webcit/groupdav_delete.c b/webcit/groupdav_delete.c index f731daa5a..8aa9f3b57 100644 --- a/webcit/groupdav_delete.c +++ b/webcit/groupdav_delete.c @@ -42,9 +42,9 @@ void groupdav_delete(char *dav_pathname, char *dav_ifmatch) { gotoroom(dav_roomname); } if (strcasecmp(WC->wc_roomname, dav_roomname)) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("Content-Length: 0\r\n\r\n"); return; } @@ -54,9 +54,9 @@ void groupdav_delete(char *dav_pathname, char *dav_ifmatch) { * If no item exists with the requested uid ... simple error. */ if (dav_msgnum < 0L) { - wprintf("HTTP/1.1 404 Not Found\r\n"); + hprintf("HTTP/1.1 404 Not Found\r\n"); groupdav_common_headers(); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("Content-Length: 0\r\n\r\n"); return; } @@ -66,9 +66,9 @@ void groupdav_delete(char *dav_pathname, char *dav_ifmatch) { */ if (!IsEmptyStr(dav_ifmatch)) { if (atol(dav_ifmatch) != dav_msgnum) { - wprintf("HTTP/1.1 412 Precondition Failed\r\n"); + hprintf("HTTP/1.1 412 Precondition Failed\r\n"); groupdav_common_headers(); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("Content-Length: 0\r\n\r\n"); return; } } @@ -79,14 +79,14 @@ void groupdav_delete(char *dav_pathname, char *dav_ifmatch) { serv_printf("DELE %ld", dav_msgnum); serv_getln(buf, sizeof buf); if (buf[0] == '2') { - wprintf("HTTP/1.1 204 No Content\r\n"); /* success */ + hprintf("HTTP/1.1 204 No Content\r\n"); /* success */ groupdav_common_headers(); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("Content-Length: 0\r\n\r\n"); } else { - wprintf("HTTP/1.1 403 Forbidden\r\n"); /* access denied */ + hprintf("HTTP/1.1 403 Forbidden\r\n"); /* access denied */ groupdav_common_headers(); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("Content-Length: 0\r\n\r\n"); } return; } diff --git a/webcit/groupdav_get.c b/webcit/groupdav_get.c index 124d44988..02d4ea26b 100644 --- a/webcit/groupdav_get.c +++ b/webcit/groupdav_get.c @@ -20,20 +20,18 @@ void groupdav_get_big_ics(void) { serv_puts("ICAL getics"); serv_getln(buf, sizeof buf); if (buf[0] != '1') { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "%s\r\n", + hprintf("Content-Type: text/plain\r\n"); + wprintf("%s\r\n", &buf[4] - ); + );/// TODO: do we need to end-burst here? return; } - wprintf("HTTP/1.1 200 OK\r\n"); + hprintf("HTTP/1.1 200 OK\r\n"); groupdav_common_headers(); - wprintf("Content-type: text/calendar; charset=UTF-8\r\n"); + hprintf("Content-type: text/calendar; charset=UTF-8\r\n"); begin_burst(); while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { wprintf("%s\r\n", buf); @@ -74,9 +72,9 @@ void extract_preferred(char *name, char *filename, char *partnum, char *disp, if (!IsEmptyStr(cbcharset)) { safestrncpy(epdata->charset, cbcharset, sizeof epdata->charset); } - wprintf("Content-type: %s; charset=%s\r\n", cbtype, epdata->charset); + hprintf("Content-type: %s; charset=%s\r\n", cbtype, epdata->charset); begin_burst(); - client_write(content, length); + StrBufAppendBufPlain(WC->WBuf, content, length, 0); end_burst(); } } @@ -107,13 +105,11 @@ void groupdav_get(char *dav_pathname) { struct epdata epdata; if (num_tokens(dav_pathname, '/') < 3) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "The object you requested was not found.\r\n" - ); + hprintf("Content-Type: text/plain\r\n"); + wprintf("The object you requested was not found.\r\n"); + end_burst(); return; } @@ -128,14 +124,12 @@ void groupdav_get(char *dav_pathname) { gotoroom(dav_roomname); } if (strcasecmp(WC->wc_roomname, dav_roomname)) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "There is no folder called \"%s\" on this server.\r\n", - dav_roomname - ); + hprintf("Content-Type: text/plain\r\n"); + wprintf("There is no folder called \"%s\" on this server.\r\n", + dav_roomname); + end_burst(); return; } @@ -150,15 +144,13 @@ void groupdav_get(char *dav_pathname) { serv_printf("MSG2 %ld", dav_msgnum); serv_getln(buf, sizeof buf); if (buf[0] != '1') { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "Object \"%s\" was not found in the \"%s\" folder.\r\n", + hprintf("Content-Type: text/plain\r\n"); + wprintf("Object \"%s\" was not found in the \"%s\" folder.\r\n", dav_uid, - dav_roomname - ); + dav_roomname); + end_burst(); return; } @@ -210,10 +202,10 @@ void groupdav_get(char *dav_pathname) { /* Output headers common to single or multi part messages */ - wprintf("HTTP/1.1 200 OK\r\n"); + hprintf("HTTP/1.1 200 OK\r\n"); groupdav_common_headers(); - wprintf("etag: \"%ld\"\r\n", dav_msgnum); - wprintf("Date: %s\r\n", date); + hprintf("etag: \"%ld\"\r\n", dav_msgnum); + hprintf("Date: %s\r\n", date); memset(&epdata, 0, sizeof(struct epdata)); safestrncpy(epdata.charset, charset, sizeof epdata.charset); @@ -241,7 +233,7 @@ void groupdav_get(char *dav_pathname) { ptr = msgtext; endptr = &msgtext[msglen]; - wprintf("Content-type: %s; charset=%s\r\n", content_type, charset); + hprintf("Content-type: %s; charset=%s\r\n", content_type, charset); in_body = 0; do { diff --git a/webcit/groupdav_main.c b/webcit/groupdav_main.c index a05c05ad2..07fb67d3c 100644 --- a/webcit/groupdav_main.c +++ b/webcit/groupdav_main.c @@ -19,7 +19,7 @@ * */ void groupdav_common_headers(void) { - wprintf( + hprintf( "Server: %s / %s\r\n" "Connection: close\r\n", PACKAGE_STRING, serv_info.serv_software @@ -127,11 +127,12 @@ void groupdav_main(struct httprequest *req, } if (!WC->logged_in) { - wprintf("HTTP/1.1 401 Unauthorized\r\n"); + hprintf("HTTP/1.1 401 Unauthorized\r\n"); groupdav_common_headers(); - wprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n", + hprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n", serv_info.serv_humannode); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("Content-Length: 0\r\n"); + end_burst(); return; } @@ -229,13 +230,12 @@ void groupdav_main(struct httprequest *req, /* * Couldn't find what we were looking for. Die in a car fire. */ - wprintf("HTTP/1.1 501 Method not implemented\r\n"); + hprintf("HTTP/1.1 501 Method not implemented\r\n"); groupdav_common_headers(); - wprintf("Content-Type: text/plain\r\n" - "\r\n" - "GroupDAV method \"%s\" is not implemented.\r\n", - dav_method - ); + hprintf("Content-Type: text/plain\r\n"); + wprintf("GroupDAV method \"%s\" is not implemented.\r\n", + dav_method); + end_burst(); } diff --git a/webcit/groupdav_propfind.c b/webcit/groupdav_propfind.c index 6d3092ae8..f9b2ce0d7 100644 --- a/webcit/groupdav_propfind.c +++ b/webcit/groupdav_propfind.c @@ -93,11 +93,11 @@ void groupdav_collection_list(char *dav_pathname, int dav_depth) * Be rude. Completely ignore the XML request and simply send them * everything we know about. Let the client sort it out. */ - wprintf("HTTP/1.0 207 Multi-Status\r\n"); + hprintf("HTTP/1.0 207 Multi-Status\r\n"); groupdav_common_headers(); - wprintf("Date: %s\r\n", datestring); - wprintf("Content-type: text/xml\r\n"); - wprintf("Content-encoding: identity\r\n"); + hprintf("Date: %s\r\n", datestring); + hprintf("Content-type: text/xml\r\n"); + hprintf("Content-encoding: identity\r\n"); begin_burst(); @@ -261,15 +261,14 @@ void groupdav_propfind(char *dav_pathname, int dav_depth, char *dav_content_type gotoroom(dav_roomname); } if (strcasecmp(WC->wc_roomname, dav_roomname)) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf("Date: %s\r\n", datestring); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "There is no folder called \"%s\" on this server.\r\n", + hprintf("Date: %s\r\n", datestring); + hprintf("Content-Type: text/plain\r\n"); + wprintf("There is no folder called \"%s\" on this server.\r\n", dav_roomname ); + end_burst(); return; } @@ -281,15 +280,14 @@ void groupdav_propfind(char *dav_pathname, int dav_depth, char *dav_content_type dav_msgnum = locate_message_by_uid(dav_uid); if (dav_msgnum < 0) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "Object \"%s\" was not found in the \"%s\" folder.\r\n", + hprintf("Content-Type: text/plain\r\n"); + wprintf("Object \"%s\" was not found in the \"%s\" folder.\r\n", dav_uid, dav_roomname ); + end_burst(); return; } @@ -297,11 +295,11 @@ void groupdav_propfind(char *dav_pathname, int dav_depth, char *dav_content_type * everything we know about (which is going to simply be the ETag and * nothing else). Let the client-side parser sort it out. */ - wprintf("HTTP/1.0 207 Multi-Status\r\n"); + hprintf("HTTP/1.0 207 Multi-Status\r\n"); groupdav_common_headers(); - wprintf("Date: %s\r\n", datestring); - wprintf("Content-type: text/xml\r\n"); - wprintf("Content-encoding: identity\r\n"); + hprintf("Date: %s\r\n", datestring); + hprintf("Content-type: text/xml\r\n"); + hprintf("Content-encoding: identity\r\n"); begin_burst(); @@ -338,11 +336,11 @@ void groupdav_propfind(char *dav_pathname, int dav_depth, char *dav_content_type * everything we know about (which is going to simply be the ETag and * nothing else). Let the client-side parser sort it out. */ - wprintf("HTTP/1.0 207 Multi-Status\r\n"); + hprintf("HTTP/1.0 207 Multi-Status\r\n"); groupdav_common_headers(); - wprintf("Date: %s\r\n", datestring); - wprintf("Content-type: text/xml\r\n"); - wprintf("Content-encoding: identity\r\n"); + hprintf("Date: %s\r\n", datestring); + hprintf("Content-type: text/xml\r\n"); + hprintf("Content-encoding: identity\r\n"); begin_burst(); diff --git a/webcit/groupdav_put.c b/webcit/groupdav_put.c index 7ab6d4cb4..dc5121f47 100644 --- a/webcit/groupdav_put.c +++ b/webcit/groupdav_put.c @@ -29,12 +29,11 @@ void groupdav_put_bigics(char *dav_content, int dav_content_length) serv_puts("ICAL putics"); serv_getln(buf, sizeof buf); if (buf[0] != '4') { - wprintf("HTTP/1.1 502 Bad Gateway\r\n"); + hprintf("HTTP/1.1 502 Bad Gateway\r\n"); groupdav_common_headers(); - wprintf("Content-type: text/plain\r\n" - "\r\n" - "%s\r\n", &buf[4] - ); + hprintf("Content-type: text/plain\r\n"); + wprintf("%s\r\n", &buf[4]); + end_burst(); return; } @@ -42,10 +41,10 @@ void groupdav_put_bigics(char *dav_content, int dav_content_length) serv_printf("\n000"); /* Report success and not much else. */ - wprintf("HTTP/1.1 204 No Content\r\n"); + hprintf("HTTP/1.1 204 No Content\r\n"); lprintf(9, "HTTP/1.1 204 No Content\r\n"); groupdav_common_headers(); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("Content-Length: 0\r\n"); } @@ -67,13 +66,11 @@ void groupdav_put(char *dav_pathname, char *dav_ifmatch, int n = 0; if (num_tokens(dav_pathname, '/') < 3) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "The object you requested was not found.\r\n" - ); + hprintf("Content-Type: text/plain\r\n"); + wprintf("The object you requested was not found.\r\n"); + end_burst(); return; } @@ -88,14 +85,12 @@ void groupdav_put(char *dav_pathname, char *dav_ifmatch, gotoroom(dav_roomname); } if (strcasecmp(WC->wc_roomname, dav_roomname)) { - wprintf("HTTP/1.1 404 not found\r\n"); + hprintf("HTTP/1.1 404 not found\r\n"); groupdav_common_headers(); - wprintf( - "Content-Type: text/plain\r\n" - "\r\n" - "There is no folder called \"%s\" on this server.\r\n", - dav_roomname - ); + hprintf("Content-Type: text/plain\r\n"); + wprintf("There is no folder called \"%s\" on this server.\r\n", + dav_roomname); + end_burst(); return; } @@ -111,11 +106,12 @@ void groupdav_put(char *dav_pathname, char *dav_ifmatch, old_msgnum = locate_message_by_uid(dav_uid); lprintf(9, "old_msgnum: %ld\n", old_msgnum); if (atol(dav_ifmatch) != old_msgnum) { - wprintf("HTTP/1.1 412 Precondition Failed\r\n"); + hprintf("HTTP/1.1 412 Precondition Failed\r\n"); lprintf(9, "HTTP/1.1 412 Precondition Failed (ifmatch=%ld, old_msgnum=%ld)\r\n", atol(dav_ifmatch), old_msgnum); groupdav_common_headers(); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("Content-Length: 0\r\n"); + end_burst(); return; } } @@ -135,12 +131,12 @@ void groupdav_put(char *dav_pathname, char *dav_ifmatch, serv_puts("ENT0 1|||4|||1|"); serv_getln(buf, sizeof buf); if (buf[0] != '8') { - wprintf("HTTP/1.1 502 Bad Gateway\r\n"); + hprintf("HTTP/1.1 502 Bad Gateway\r\n"); groupdav_common_headers(); - wprintf("Content-type: text/plain\r\n" - "\r\n" - "%s\r\n", &buf[4] - ); + hprintf("Content-type: text/plain\r\n"); + + wprintf("%s\r\n", &buf[4]); + end_burst(); return; } @@ -169,46 +165,44 @@ void groupdav_put(char *dav_pathname, char *dav_ifmatch, /* Citadel failed in some way? */ if (new_msgnum < 0L) { - wprintf("HTTP/1.1 502 Bad Gateway\r\n"); + hprintf("HTTP/1.1 502 Bad Gateway\r\n"); groupdav_common_headers(); - wprintf("Content-type: text/plain\r\n" - "\r\n" - "new_msgnum is %ld\r\n" - "\r\n", new_msgnum - ); + hprintf("Content-type: text/plain\r\n"); + wprintf("new_msgnum is %ld\r\n" + "\r\n", new_msgnum); + end_burst(); return; } /* We created this item for the first time. */ if (old_msgnum < 0L) { - wprintf("HTTP/1.1 201 Created\r\n"); + hprintf("HTTP/1.1 201 Created\r\n"); lprintf(9, "HTTP/1.1 201 Created\r\n"); groupdav_common_headers(); - wprintf("etag: \"%ld\"\r\n", new_msgnum); - wprintf("Content-Length: 0\r\n"); - wprintf("Location: "); + hprintf("etag: \"%ld\"\r\n", new_msgnum); + hprintf("Content-Length: 0\r\n"); + hprintf("Location: "); groupdav_identify_host(); - wprintf("/groupdav/"); + hprintf("/groupdav/");/////TODO urlescputs(dav_roomname); char escaped_uid[1024]; euid_escapize(escaped_uid, dav_uid); wprintf("/%s\r\n", escaped_uid); - wprintf("\r\n"); return; } /* We modified an existing item. */ - wprintf("HTTP/1.1 204 No Content\r\n"); + hprintf("HTTP/1.1 204 No Content\r\n"); lprintf(9, "HTTP/1.1 204 No Content\r\n"); groupdav_common_headers(); - wprintf("etag: \"%ld\"\r\n", new_msgnum); - wprintf("Content-Length: 0\r\n\r\n"); + hprintf("etag: \"%ld\"\r\n", new_msgnum); + hprintf("Content-Length: 0\r\n"); /* The item we replaced has probably already been deleted by * the Citadel server, but we'll do this anyway, just in case. */ serv_printf("DELE %ld", old_msgnum); serv_getln(buf, sizeof buf); - + end_burst(); return; } diff --git a/webcit/html2html.c b/webcit/html2html.c index c65e674bc..0db2374a1 100644 --- a/webcit/html2html.c +++ b/webcit/html2html.c @@ -467,7 +467,7 @@ void output_html(char *supplied_charset, int treat_as_wiki) { /** output_length = content_length; */ /** Output our big pile of markup */ - client_write(converted_msg, output_length); + StrBufAppendBufPlain(WC->WBuf, converted_msg, output_length, 0); BAIL: /** A little trailing vertical whitespace... */ wprintf("

\n"); diff --git a/webcit/messages.c b/webcit/messages.c index 06ca707ca..903408964 100644 --- a/webcit/messages.c +++ b/webcit/messages.c @@ -1411,13 +1411,13 @@ void print_message(void) { msgnum = StrTol(WC->UrlFragment1); output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-type: text/html\r\n" + hprintf("Content-type: text/html\r\n" "Server: %s\r\n" - "Connection: close\r\n", + "Connection: close\r\n" PACKAGE_STRING); begin_burst(); - wprintf("\r\n\r\n\n"); + wprintf("\r\n<html>\n<head><title>"); escputs(WC->wc_fullname); wprintf("\n" "\n" @@ -1443,7 +1443,7 @@ void display_headers(void) { msgnum = StrTol(WC->UrlFragment1); output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-type: text/plain\r\n" + hprintf("Content-type: text/plain\r\n" "Server: %s\r\n" "Connection: close\r\n", PACKAGE_STRING); diff --git a/webcit/paging.c b/webcit/paging.c index 1d79cddf5..502f9c069 100644 --- a/webcit/paging.c +++ b/webcit/paging.c @@ -277,8 +277,7 @@ void chat_recv(void) { output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-type: text/html; charset=utf-8\n"); - wprintf("\n"); + hprintf("Content-type: text/html; charset=utf-8\r\n"); wprintf("\n" "\n" "\n" @@ -425,8 +424,7 @@ void chat_send(void) { char buf[SIZ]; output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-type: text/html; charset=utf-8\n"); - wprintf("\n"); + hprintf("Content-type: text/html; charset=utf-8\r\n"); wprintf("" "" ); diff --git a/webcit/rss.c b/webcit/rss.c index 73297a549..062227d18 100644 --- a/webcit/rss.c +++ b/webcit/rss.c @@ -91,20 +91,20 @@ void display_rss(char *roomname, char *request_method) if (gotoroom((char *)roomname)) { lprintf(3, "RSS: Can't goto requested room\n"); - wprintf("HTTP/1.1 404 Not Found\r\n"); - wprintf("Content-Type: text/html\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 404 Not Found\r\n"); + hprintf("Content-Type: text/html\r\n"); wprintf("Error retrieving RSS feed: couldn't find room\n"); + end_burst(); return; } nummsgs = load_msg_ptrs("MSGS LAST|15", 0); if (nummsgs == 0) { lprintf(3, "RSS: No messages found\n"); - wprintf("HTTP/1.1 404 Not Found\r\n"); - wprintf("Content-Type: text/html\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 404 Not Found\r\n"); + hprintf("Content-Type: text/html\r\n"); wprintf(_("Error retrieving RSS feed: couldn't find messages\n")); + end_burst(); return; } @@ -127,26 +127,25 @@ void display_rss(char *roomname, char *request_method) // Commented out. Play dumb for now, also doesn't work with anonrss hack /* if (if_modified_since > 0 && if_modified_since > now) { lprintf(3, "RSS: Feed not updated since the last time you looked\n"); - wprintf("HTTP/1.1 304 Not Modified\r\n"); - wprintf("Last-Modified: %s\r\n", date); + hprintf("HTTP/1.1 304 Not Modified\r\n"); + hprintf("Last-Modified: %s\r\n", date); now = time(NULL); gmtime_r(&now, &now_tm); strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", &now_tm); - wprintf("Date: %s\r\n", date); - if (*msgn) wprintf("ETag: %s\r\n\r\n", msgn); */ + hprintf("Date: %s\r\n", date); + if (*msgn) hprintf("ETag: %s\r\n", msgn); */ // wDumpContent(0); // return; //} /* Do RSS header */ lprintf(3, "RSS: Yum yum! This feed is tasty!\n"); - wprintf("HTTP/1.1 200 OK\r\n"); - wprintf("Last-Modified: %s\r\n", date); + hprintf("HTTP/1.1 200 OK\r\n"); + hprintf("Last-Modified: %s\r\n", date); /* if (*msgn) wprintf("ETag: %s\r\n\r\n", msgn); */ - wprintf("Content-Type: application/rss+xml\r\n"); - wprintf("Server: %s\r\n", PACKAGE_STRING); - wprintf("Connection: close\r\n"); - wprintf("\r\n"); + hprintf("Content-Type: application/rss+xml\r\n"); + hprintf("Server: %s\r\n", PACKAGE_STRING); + hprintf("Connection: close\r\n"); if (!strcasecmp(request_method, "HEAD")) return; diff --git a/webcit/serv_func.c b/webcit/serv_func.c index 9e7f0524f..a5604c225 100644 --- a/webcit/serv_func.c +++ b/webcit/serv_func.c @@ -339,34 +339,52 @@ void server_to_text() /** * Read binary data from server into memory using a series of * server READ commands. - * \param buffer the output buffer - * \param total_len the maximal length of buffer + * \return the read content as StrBuf */ -void read_server_binary(char *buffer, size_t total_len) { +StrBuf *read_server_binary(size_t total_len) +{ char buf[SIZ]; size_t bytes = 0; size_t thisblock = 0; + StrBuf *Buf; + StrBuf *Ret = NULL; - memset(buffer, 0, total_len); + Buf = NewStrBuf(); + while (bytes < total_len) { thisblock = 4095; if ((total_len - bytes) < thisblock) { thisblock = total_len - bytes; - if (thisblock == 0) return; + if (thisblock == 0) { + FreeStrBuf(&Ret); + FreeStrBuf(&Buf); + return NULL; + } } serv_printf("READ %d|%d", (int)bytes, (int)thisblock); - serv_getln(buf, sizeof buf); - if (buf[0] == '6') { - thisblock = (size_t)atoi(&buf[4]); - if (!WC->connected) return; - serv_read(&buffer[bytes], thisblock); - bytes += thisblock; - } - else { - lprintf(3, "Error: %s\n", &buf[4]); - return; + if (StrBuf_ServGetln(Buf) > 0) + { + if (ChrPtr(Buf)[0] == '6') + { + StrBufCutLeft(Buf, 4); //thisblock = (size_t)atoi(&buf[4]); + thisblock = StrTol(Buf); + if (!WC->connected) { + FreeStrBuf(&Ret); + FreeStrBuf(&Buf); + return NULL; + } + if (Ret == NULL) Ret = NewStrBuf(); + StrBuf_ServGetBLOB(Ret, thisblock); + bytes += thisblock; + } + else { + FreeStrBuf(&Buf); + lprintf(3, "Error: %s\n", &buf[4]); + return NULL; + } } } + return Ret; } @@ -375,36 +393,27 @@ void read_server_binary(char *buffer, size_t total_len) { * usual 000 terminator is found. Caller is responsible for freeing * the returned pointer. */ -char *read_server_text(void) { - char *text = NULL; - size_t bytes_allocated = 0; - size_t bytes_read = 0; - int linelen; - char buf[SIZ]; - - text = malloc(SIZ); - if (text == NULL) { - return(NULL); - } - text[0] = 0; - bytes_allocated = SIZ; - - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { - linelen = strlen(buf); - buf[linelen] = '\n'; - buf[linelen+1] = 0; - ++linelen; - - if ((bytes_read + linelen) >= (bytes_allocated - 2)) { - bytes_allocated = 2 * bytes_allocated; - text = realloc(text, bytes_allocated); - } - - strcpy(&text[bytes_read], buf); - bytes_read += linelen; +StrBuf *read_server_text(long *nLines) +{ + struct wcsession *WCC = WC; + StrBuf *Buf; + long nRead; + long nlines; + const char *buf; + + Buf = NewStrBuf(); + buf = ChrPtr(Buf); + nlines = 0; + while ((WCC->serv_sock!=-1) && + (nRead = StrBuf_ServGetln(Buf)), + (nRead >= 0) && + (buf += nRead), (strcmp(buf, "000") != 0)) { + + nlines ++; } - return(text); + *nLines = nlines; + return Buf; } diff --git a/webcit/siteconfig.c b/webcit/siteconfig.c index 5a2ee2e6f..de3e640de 100644 --- a/webcit/siteconfig.c +++ b/webcit/siteconfig.c @@ -15,6 +15,7 @@ void display_siteconfig(void) { char buf[SIZ]; int i, j; + struct wcsession *WCC = WC; char general[65536]; char access[SIZ]; @@ -113,7 +114,7 @@ void display_siteconfig(void) ); wprintf("
\n"); - wprintf("\n", WC->nonce); + wprintf("\n", WCC->nonce); sprintf(&general[strlen(general)], " %s ", _("Change Login Logo")); sprintf(&general[strlen(general)], " %s \n", _("Change Logout Logo")); @@ -729,15 +730,15 @@ void display_siteconfig(void) tabbed_dialog(9, tabnames); - begin_tab(0, 9); client_write(general, strlen(general)); end_tab(0, 9); - begin_tab(1, 9); client_write(access, strlen(access)); end_tab(1, 9); - begin_tab(2, 9); client_write(network, strlen(network)); end_tab(2, 9); - begin_tab(3, 9); client_write(tuning, strlen(tuning)); end_tab(3, 9); - begin_tab(4, 9); client_write(directory, strlen(directory)); end_tab(4, 9); - begin_tab(5, 9); client_write(purger, strlen(purger)); end_tab(5, 9); - begin_tab(6, 9); client_write(idxjnl, strlen(idxjnl)); end_tab(6, 9); - begin_tab(7, 9); client_write(funambol, strlen(funambol)); end_tab(7, 9); - begin_tab(8, 9); client_write(pop3, strlen(pop3)); end_tab(8, 9); + begin_tab(0, 9); StrBufAppendBufPlain(WCC->WBuf, general, strlen(general), 0); end_tab(0, 9); + begin_tab(1, 9); StrBufAppendBufPlain(WCC->WBuf, access, strlen(access), 0); end_tab(1, 9); + begin_tab(2, 9); StrBufAppendBufPlain(WCC->WBuf, network, strlen(network), 0); end_tab(2, 9); + begin_tab(3, 9); StrBufAppendBufPlain(WCC->WBuf, tuning, strlen(tuning), 0); end_tab(3, 9); + begin_tab(4, 9); StrBufAppendBufPlain(WCC->WBuf, directory, strlen(directory), 0); end_tab(4, 9); + begin_tab(5, 9); StrBufAppendBufPlain(WCC->WBuf, purger, strlen(purger), 0); end_tab(5, 9); + begin_tab(6, 9); StrBufAppendBufPlain(WCC->WBuf, idxjnl, strlen(idxjnl), 0); end_tab(6, 9); + begin_tab(7, 9); StrBufAppendBufPlain(WCC->WBuf, funambol, strlen(funambol), 0); end_tab(7, 9); + begin_tab(8, 9); StrBufAppendBufPlain(WCC->WBuf, pop3, strlen(pop3), 0); end_tab(8, 9); wprintf("
"); wprintf("", _("Save changes")); wprintf(" "); diff --git a/webcit/tcp_sockets.c b/webcit/tcp_sockets.c index e94c8a5fa..fa5429d32 100644 --- a/webcit/tcp_sockets.c +++ b/webcit/tcp_sockets.c @@ -182,7 +182,7 @@ int StrBuf_ServGetln(StrBuf *buf) const char *ErrStr; int rc; - rc = StrBufTCP_read_line(buf, WC->serv_sock, 0, &ErrStr); + rc = StrBufTCP_read_line(buf, &WC->serv_sock, 0, &ErrStr); if (rc < 0) { lprintf(1, "Server connection broken: %s\n", @@ -195,6 +195,24 @@ int StrBuf_ServGetln(StrBuf *buf) return rc; } +int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize) +{ + const char *Err; + int rc; + + rc = StrBufReadBLOB(buf, &WC->serv_sock, 1, BlobSize, &Err); + if (rc < 0) + { + lprintf(1, "Server connection broken: %s\n", + Err); + wc_backtrace(); + WC->serv_sock = (-1); + WC->connected = 0; + WC->logged_in = 0; + } + return rc; +} + /** * \brief send binary to server * \param buf the buffer to write to citadel server diff --git a/webcit/webcit.c b/webcit/webcit.c index 2660b3d2f..27edb1a3d 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -5,7 +5,8 @@ * persistent session to the Citadel server, handling HTTP WebCit requests as * they arrive and presenting a user interface. */ - +#include +#define SHOW_ME_VAPPEND_PRINTF #include "webcit.h" #include "groupdav.h" #include "webserver.h" @@ -326,14 +327,34 @@ int YESBSTR(char *key) */ void wprintf(const char *format,...) { + struct wcsession *WCC = WC; + va_list arg_ptr; + + if (WCC->WBuf == NULL) + WCC->WBuf = NewStrBuf(); + + va_start(arg_ptr, format); + StrBufVAppendPrintf(WCC->WBuf, format, arg_ptr); + va_end(arg_ptr); + +/// if (StrLength(WCC-WBuf) > 2048) + ///client_write(wbuf, strlen(wbuf)); +} + +/* + * http-header-printing funcion. uses our vsnprintf wrapper + */ +void hprintf(const char *format,...) +{ + struct wcsession *WCC = WC; va_list arg_ptr; - char wbuf[4096]; va_start(arg_ptr, format); - vsnprintf(wbuf, sizeof wbuf, format, arg_ptr); + StrBufVAppendPrintf(WCC->HBuf, format, arg_ptr); va_end(arg_ptr); - client_write(wbuf, strlen(wbuf)); +/// if (StrLength(WCC-WBuf) > 2048) + ///client_write(wbuf, strlen(wbuf)); } @@ -632,11 +653,11 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers char cookie[1024]; char httpnow[128]; - wprintf("HTTP/1.1 200 OK\n"); + hprintf("HTTP/1.1 200 OK\n"); http_datestring(httpnow, sizeof httpnow, time(NULL)); if (do_httpheaders) { - wprintf("Content-type: text/html; charset=utf-8\r\n" + hprintf("Content-type: text/html; charset=utf-8\r\n" "Server: %s / %s\n" "Connection: close\r\n", PACKAGE_STRING, serv_info.serv_software @@ -649,7 +670,7 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers http_datestring(httpTomorow, sizeof httpTomorow, time(NULL) + 60 * 60 * 24 * 2); - wprintf("Pragma: public\r\n" + hprintf("Pragma: public\r\n" "Cache-Control: max-age=3600, must-revalidate\r\n" "Last-modified: %s\r\n" "Expires: %s\r\n", @@ -658,7 +679,7 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers ); } else { - wprintf("Pragma: no-cache\r\n" + hprintf("Pragma: no-cache\r\n" "Cache-Control: no-store\r\n" "Expires: -1\r\n" ); @@ -668,11 +689,11 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers WC->wc_password, WC->wc_roomname); if (unset_cookies) { - wprintf("Set-cookie: webcit=%s; path=/\r\n", unset); + hprintf("Set-cookie: webcit=%s; path=/\r\n", unset); } else { - wprintf("Set-cookie: webcit=%s; path=/\r\n", cookie); + hprintf("Set-cookie: webcit=%s; path=/\r\n", cookie); if (server_cookie != NULL) { - wprintf("%s\n", server_cookie); + hprintf("%s\n", server_cookie); } } @@ -728,13 +749,14 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers * Generic function to do an HTTP redirect. Easy and fun. */ void http_redirect(const char *whichpage) { - wprintf("HTTP/1.1 302 Moved Temporarily\n"); - wprintf("Location: %s\r\n", whichpage); - wprintf("URI: %s\r\n", whichpage); - wprintf("Content-type: text/html; charset=utf-8\r\n\r\n"); + hprintf("HTTP/1.1 302 Moved Temporarily\n"); + hprintf("Location: %s\r\n", whichpage); + hprintf("URI: %s\r\n", whichpage); + hprintf("Content-type: text/html; charset=utf-8\r\n"); wprintf(""); wprintf("Go here.", whichpage); wprintf("\n"); + end_burst(); } @@ -742,48 +764,20 @@ void http_redirect(const char *whichpage) { /* * Output a piece of content to the web browser using conformant HTTP and MIME semantics */ -void http_transmit_thing(char *thing, size_t length, const char *content_type, +void http_transmit_thing(StrBuf *thing, const char *content_type, int is_static) { output_headers(0, 0, 0, 0, 0, is_static); - wprintf("Content-type: %s\r\n" + hprintf("Content-type: %s\r\n" "Server: %s\r\n" "Connection: close\r\n", content_type, PACKAGE_STRING); -#ifdef HAVE_ZLIB - /* If we can send the data out compressed, please do so. */ - if (WC->gzip_ok) { - char *compressed_data = NULL; - size_t compressed_len; - - compressed_len = ((length * 101) / 100) + 100; - compressed_data = malloc(compressed_len); - - if (compress_gzip((Bytef *) compressed_data, - &compressed_len, - (Bytef *) thing, - (uLongf) length, Z_BEST_SPEED) == Z_OK) { - wprintf("Content-encoding: gzip\r\n" - "Content-length: %ld\r\n" - "\r\n", - (long) compressed_len - ); - client_write(compressed_data, (size_t)compressed_len); - free(compressed_data); - return; - } - } -#endif - - /* No compression ... just send it out as-is */ - wprintf("Content-length: %ld\r\n" - "\r\n", - (long) length - ); - client_write(thing, (size_t)length); + WC->WBuf = thing; + end_burst(); + WC->WBuf = NULL; } /* @@ -826,60 +820,60 @@ void print_menu_box(char* Title, char *Class, int nLines, ...) */ void output_static(char *what) { - FILE *fp; + int fd; struct stat statbuf; off_t bytes; off_t count = 0; - size_t res; - char *bigbuffer; + StrBuf *Buf; const char *content_type; int len; + const char *Err; - fp = fopen(what, "rb"); - if (fp == NULL) { + fd = open(what, O_RDONLY); + if (fd <= 0) { lprintf(9, "output_static('%s') -- NOT FOUND --\n", what); - wprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); + hprintf("Content-Type: text/plain\r\n"); wprintf("Cannot open %s: %s\r\n", what, strerror(errno)); + end_burst(); } else { len = strlen (what); content_type = GuessMimeByFilename(what, len); - if (fstat(fileno(fp), &statbuf) == -1) { + if (fstat(fd, &statbuf) == -1) { lprintf(9, "output_static('%s') -- FSTAT FAILED --\n", what); - wprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); + hprintf("Content-Type: text/plain\r\n"); wprintf("Cannot fstat %s: %s\n", what, strerror(errno)); + end_burst(); return; } count = 0; bytes = statbuf.st_size; - if ((bigbuffer = malloc(bytes + 2)) == NULL) { + Buf = NewStrBufPlain(NULL, bytes + 2); + if (Buf == NULL) { lprintf(9, "output_static('%s') -- MALLOC FAILED (%s) --\n", what, strerror(errno)); - wprintf("HTTP/1.1 500 internal server error\r\n"); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 500 internal server error\r\n"); + hprintf("Content-Type: text/plain\r\n"); + end_burst(); return; } - while (count < bytes) { - if ((res = fread(bigbuffer + count, 1, bytes - count, fp)) == 0) { - lprintf(9, "output_static('%s') -- FREAD FAILED (%s) %zu bytes of %zu --\n", what, strerror(errno), bytes - count, bytes); - wprintf("HTTP/1.1 500 internal server error \r\n"); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); +/// StrBufAppendBuf(Buf, WC->WBuf, 0); + if (StrBufReadBLOB(Buf, &fd, 1, bytes, &Err) < 0) + { + lprintf(9, "output_static('%s') -- FREAD FAILED (%s) --\n", what, strerror(errno)); + hprintf("HTTP/1.1 500 internal server error \r\n"); + hprintf("Content-Type: text/plain\r\n"); + end_burst(); return; - } - count += res; } - fclose(fp); + close(fd); lprintf(9, "output_static('%s') %s\n", what, content_type); - http_transmit_thing(bigbuffer, (size_t)bytes, content_type, 1); - free(bigbuffer); + http_transmit_thing(Buf, content_type, 1); + FreeStrBuf(&Buf); } if (yesbstr("force_close_session")) { end_webcit_session(); @@ -896,6 +890,7 @@ void output_image() char *xferbuf = NULL; off_t bytes; const char *MimeType; + StrBuf *Buf; serv_printf("OIMG %s|%s", bstr("name"), bstr("parm")); serv_getln(buf, sizeof buf); @@ -904,23 +899,22 @@ void output_image() xferbuf = malloc(bytes + 2); /** Read it from the server */ - read_server_binary(xferbuf, bytes); + + Buf = read_server_binary(bytes); serv_puts("CLOS"); serv_getln(buf, sizeof buf); - MimeType = GuessMimeType (xferbuf, bytes); + MimeType = GuessMimeType (ChrPtr(Buf), StrLength(Buf)); /** Write it to the browser */ if (!IsEmptyStr(MimeType)) { - http_transmit_thing(xferbuf, - (size_t)bytes, + http_transmit_thing(Buf, MimeType, 0); - free(xferbuf); + FreeStrBuf(&Buf); return; } /* hm... unknown mimetype? fallback to blank gif */ - free(xferbuf); } @@ -942,9 +936,10 @@ void display_vcard_photo_img(void) char *vcard; struct vCard *v; char *xferbuf; - char *photosrc; + char *photosrc; int decoded; const char *contentType; + StrBuf *Buf; msgnum = StrTol(WC->UrlFragment1); @@ -963,10 +958,12 @@ void display_vcard_photo_img(void) photosrc, strlen(photosrc)); contentType = GuessMimeType(xferbuf, decoded); - http_transmit_thing(xferbuf, decoded, contentType, 0); + Buf = _NewConstStrBuf(xferbuf, decoded); + http_transmit_thing(Buf, contentType, 0); free(v); free(photosrc); free(xferbuf); + FreeStrBuf(&Buf); } /* @@ -987,6 +984,7 @@ void mimepart(const char *msgnum, const char *partnum, int force_download) serv_printf("OPNA %s|%s", msgnum, partnum); serv_getln(buf, sizeof buf); if (buf[0] == '2') { + StrBuf *Buf; bytes = extract_long(&buf[4], 0); content = malloc(bytes + 2); if (force_download) { @@ -996,17 +994,18 @@ void mimepart(const char *msgnum, const char *partnum, int force_download) extract_token(content_type, &buf[4], 3, '|', sizeof content_type); } output_headers(0, 0, 0, 0, 0, 0); - read_server_binary(content, bytes); + + Buf = read_server_binary(bytes); serv_puts("CLOS"); serv_getln(buf, sizeof buf); - http_transmit_thing(content, bytes, content_type, 0); - free(content); + http_transmit_thing(Buf, content_type, 0); + FreeStrBuf(&Buf); } else { - wprintf("HTTP/1.1 404 %s\n", &buf[4]); + hprintf("HTTP/1.1 404 %s\n", &buf[4]); output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("Content-Type: text/plain\r\n"); wprintf(_("An error occurred while retrieving this part: %s\n"), &buf[4]); + end_burst(); } } @@ -1050,7 +1049,7 @@ char *load_mimepart(long msgnum, char *partnum) */ void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext) { - wprintf("HTTP/1.1 200 OK\n"); + hprintf("HTTP/1.1 200 OK\n"); output_headers(1, 1, 2, 0, 0, 0); wprintf("
\n"); wprintf("
", titlebarcolor); @@ -1138,15 +1137,16 @@ void display_success(char *successmessage) */ void authorization_required(const char *message) { - wprintf("HTTP/1.1 401 Authorization Required\r\n"); - wprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n", serv_info.serv_humannode); - wprintf("Content-Type: text/html\r\n\r\n"); + hprintf("HTTP/1.1 401 Authorization Required\r\n"); + hprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n", serv_info.serv_humannode); + hprintf("Content-Type: text/html\r\n"); wprintf("

"); wprintf(_("Authorization Required")); wprintf("

\r\n"); wprintf(_("The resource you requested requires a valid username and password. " "You could not be logged in: %s\n"), message); wDumpContent(0); + } /* @@ -1215,7 +1215,7 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, void begin_ajax_response(void) { output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-type: text/html; charset=UTF-8\r\n" + hprintf("Content-type: text/html; charset=UTF-8\r\n" "Server: %s\r\n" "Connection: close\r\n" "Pragma: no-cache\r\n" @@ -1230,7 +1230,7 @@ void begin_ajax_response(void) { * print ajax response footer */ void end_ajax_response(void) { - wprintf("\r\n"); + ///hprintf("\r\n");///// todo: is this right? wDumpContent(0); } @@ -1367,8 +1367,8 @@ void session_loop(struct httprequest *req) char c_httpauth_user[SIZ]; char c_httpauth_pass[SIZ]; char cookie[SIZ]; - struct wcsession *WCC = WC; - + struct wcsession *WCC; + safestrncpy(c_username, "", sizeof c_username); safestrncpy(c_password, "", sizeof c_password); safestrncpy(c_roomname, "", sizeof c_roomname); @@ -1377,6 +1377,10 @@ void session_loop(struct httprequest *req) safestrncpy(c_httpauth_pass, DEFAULT_HTTPAUTH_PASS, sizeof c_httpauth_pass); strcpy(browser_host, ""); + WCC= WC; + if (WCC->HBuf == NULL) + WCC->HBuf = NewStrBuf(); + FlushStrBuf(WCC->HBuf); WCC->upload_length = 0; WCC->upload = NULL; WCC->is_mobile = 0; @@ -1507,10 +1511,10 @@ void session_loop(struct httprequest *req) /* If it's a "force 404" situation then display the error and bail. */ if (!strcmp(action, "404")) { - wprintf("HTTP/1.1 404 Not found\r\n"); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 404 Not found\r\n"); + hprintf("Content-Type: text/plain\r\n"); wprintf("Not found\r\n"); + end_burst(); goto SKIP_ALL_THIS_CRAP; } @@ -1543,10 +1547,10 @@ void session_loop(struct httprequest *req) else { lprintf(9, "Suspicious request. Ignoring."); - wprintf("HTTP/1.1 404 Security check failed\r\n"); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 404 Security check failed\r\n"); + hprintf("Content-Type: text/plain\r\n"); wprintf("You have sent a malformed or invalid request.\r\n"); + end_burst(); } goto SKIP_ALL_THIS_CRAP; /* Don't try to connect */ } @@ -1557,10 +1561,10 @@ void session_loop(struct httprequest *req) bstr("nonce"), WCC->nonce); if (ibstr("nonce") != WCC->nonce) { lprintf(9, "Ignoring request with mismatched nonce.\n"); - wprintf("HTTP/1.1 404 Security check failed\r\n"); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 404 Security check failed\r\n"); + hprintf("Content-Type: text/plain\r\n"); wprintf("Security check failed.\r\n"); + end_burst(); goto SKIP_ALL_THIS_CRAP; } } diff --git a/webcit/webcit.h b/webcit/webcit.h index b8353a90b..d57b83808 100644 --- a/webcit/webcit.h +++ b/webcit/webcit.h @@ -410,9 +410,6 @@ struct wcsession { int ctdl_pid; /**< Session ID on the Citadel server */ char httpauth_user[256]; /**< only for GroupDAV sessions */ char httpauth_pass[256]; /**< only for GroupDAV sessions */ - size_t burst_len; /** current_iconbar */ @@ -543,6 +542,7 @@ void output_headers( int do_httpheaders, int suppress_check, int cache); void wprintf(const char *format,...)__attribute__((__format__(__printf__,1,2))); +void hprintf(const char *format,...)__attribute__((__format__(__printf__,1,2))); void output_static(char *what); void display_mime_icon(void); void print_menu_box(char* Title, char *Class, int nLines, ...); @@ -703,13 +703,13 @@ void initialize_locales(void); extern char *months[]; extern char *days[]; -void read_server_binary(char *buffer, size_t total_len); -char *read_server_text(void); +StrBuf *read_server_binary(size_t total_len); +int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize); +StrBuf *read_server_text(long *nLines); int goto_config_room(void); long locate_user_vcard(char *username, long usernum); void sleeeeeeeeeep(int); -void http_transmit_thing(char *thing, size_t length, const char *content_type, - int is_static); +void http_transmit_thing(StrBuf *thing, const char *content_type, int is_static); long unescape_input(char *buf); void do_selected_iconbar(void); int CtdlDecodeQuotedPrintable(char *decoded, char *encoded, int sourcelen); @@ -752,7 +752,7 @@ void ssl_lock(int mode, int n, const char *file, int line); int starttls(int sock); extern SSL_CTX *ssl_ctx; int client_read_ssl(char *buf, int bytes, int timeout); -void client_write_ssl(char *buf, int nbytes); +void client_write_ssl(const char *buf, int nbytes); #endif #ifdef HAVE_ZLIB @@ -764,7 +764,7 @@ int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen, void utf8ify_rfc822_string(char *buf); void begin_burst(void); -void end_burst(void); +long end_burst(void); extern char *hourname[]; /**< Names of hours (12am, 1am, etc.) */ diff --git a/webcit/webserver.c b/webcit/webserver.c index 4f3605127..99cdfc256 100644 --- a/webcit/webserver.c +++ b/webcit/webserver.c @@ -238,210 +238,126 @@ int client_read_to(int sock, char *buf, int bytes, int timeout) } /* - * write data to the client + * \brief Begin buffering HTTP output so we can transmit it all in one write operation later. */ -ssize_t client_write(const void *buf, size_t count) +void begin_burst(void) +{ + WC->WBuf = NewStrBufPlain(NULL, 32768); +} + + +/* + * \brief Finish buffering HTTP output. [Compress using zlib and] output with a Content-Length: header. + */ +long end_burst(void) { - char *newptr; - size_t newalloc; - size_t bytesWritten = 0; - ssize_t res; + struct wcsession *WCC = WC; + const char *ptr, *eptr; + long count; + ssize_t res; fd_set wset; int fdflags; - if (WC->burst != NULL) { - if ((WC->burst_len + count) >= WC->burst_alloc) { - newalloc = (WC->burst_alloc * 2); - if ((WC->burst_len + count) >= newalloc) { - newalloc += count; - } - newptr = realloc(WC->burst, newalloc); - if (newptr != NULL) { - WC->burst = newptr; - WC->burst_alloc = newalloc; - } - } - if ((WC->burst_len + count) < WC->burst_alloc) { - memcpy(&WC->burst[WC->burst_len], buf, count); - WC->burst_len += count; - return (count); - } - else { - return(-1); - } +#ifdef HAVE_ZLIB + /* Perform gzip compression, if enabled and supported by client */ + if ((WCC->gzip_ok) && CompressBuffer(WCC->WBuf)) + { + hprintf("Content-encoding: gzip\r\n"); } +#endif /* HAVE_ZLIB */ + + hprintf("Content-length: %d\r\n\r\n", StrLength(WCC->WBuf)); + + ptr = ChrPtr(WCC->HBuf); + count = StrLength(WCC->HBuf); + eptr = ptr + count; + #ifdef HAVE_OPENSSL if (is_https) { - client_write_ssl((char *) buf, count); + client_write_ssl(ptr, StrLength(WCC->HBuf)); return (count); } #endif + + #ifdef HTTP_TRACING + write(2, "\033[34m", 5); - write(2, buf, count); + write(2, ptr, StrLength(WCC->WBuf)); write(2, "\033[30m", 5); #endif fdflags = fcntl(WC->http_sock, F_GETFL); - while (bytesWritten < count) { + while (ptr < eptr) { if ((fdflags & O_NONBLOCK) == O_NONBLOCK) { FD_ZERO(&wset); - FD_SET(WC->http_sock, &wset); - if (select(WC->http_sock + 1, NULL, &wset, NULL, NULL) == -1) { + FD_SET(WCC->http_sock, &wset); + if (select(WCC->http_sock + 1, NULL, &wset, NULL, NULL) == -1) { lprintf(2, "client_write: Socket select failed (%s)\n", strerror(errno)); return -1; } } - if ((res = write(WC->http_sock, (char*)buf + bytesWritten, - count - bytesWritten)) == -1) { + if ((res = write(WCC->http_sock, + ptr, + count)) == -1) { lprintf(2, "client_write: Socket write failed (%s)\n", strerror(errno)); return res; } - bytesWritten += res; + count -= res; + ptr += res; } - return bytesWritten; -} - -/* - * Begin buffering HTTP output so we can transmit it all in one write operation later. - * - * We do this in userspace instead of using TCP_CORK for two reasons: - * 1. We need to calculate the Content-length: header - * 2. We may want to compress the data before sending it - * - */ -void begin_burst(void) -{ - if (WC->burst != NULL) { - free(WC->burst); - WC->burst = NULL; - } - WC->burst_len = 0; - WC->burst_alloc = 32768; - WC->burst = malloc(WC->burst_alloc); -} - + ptr = ChrPtr(WCC->WBuf); + count = StrLength(WCC->WBuf); + eptr = ptr + count; -/* - * uses the same calling syntax as compress2(), but it - * creates a stream compatible with HTTP "Content-encoding: gzip" - */ -#ifdef HAVE_ZLIB -#define DEF_MEM_LEVEL 8 -#define OS_CODE 0x03 /* unix */ -int ZEXPORT compress_gzip(Bytef * dest, /* compressed buffer */ - size_t * destLen, /* length of the compresed data */ - const Bytef * source, /* source to encode */ - uLong sourceLen, /* length of source to encode */ - int level) /* compression level */ -{ - const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */ - - /* write gzip header */ - snprintf((char *) dest, *destLen, - "%c%c%c%c%c%c%c%c%c%c", - gz_magic[0], gz_magic[1], Z_DEFLATED, - 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ , - OS_CODE); - - /* normal deflate */ - z_stream stream; - int err; - stream.next_in = (Bytef *) source; - stream.avail_in = (uInt) sourceLen; - stream.next_out = dest + 10L; // after header - stream.avail_out = (uInt) * destLen; - if ((uLong) stream.avail_out != *destLen) - return Z_BUF_ERROR; - - stream.zalloc = (alloc_func) 0; - stream.zfree = (free_func) 0; - stream.opaque = (voidpf) 0; - - err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS, - DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); - if (err != Z_OK) - return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out + 10L; - - /* write CRC and Length */ - uLong crc = crc32(0L, source, sourceLen); - int n; - for (n = 0; n < 4; ++n, ++*destLen) { - dest[*destLen] = (int) (crc & 0xff); - crc >>= 8; - } - uLong len = stream.total_in; - for (n = 0; n < 4; ++n, ++*destLen) { - dest[*destLen] = (int) (len & 0xff); - len >>= 8; +#ifdef HAVE_OPENSSL + if (is_https) { + client_write_ssl(ptr, StrLength(WCC->HBuf)); + return (count); } - err = deflateEnd(&stream); - return err; -} #endif -/* - * Finish buffering HTTP output. [Compress using zlib and] output with a Content-Length: header. - */ -void end_burst(void) -{ - size_t the_len; - char *the_data; - - if (WC->burst == NULL) - return; - - the_len = WC->burst_len; - the_data = WC->burst; +#ifdef HTTP_TRACING + + write(2, "\033[34m", 5); + write(2, ptr, StrLength(WCC->WBuf)); + write(2, "\033[30m", 5); +#endif - WC->burst_len = 0; - WC->burst_alloc = 0; - WC->burst = NULL; + while (ptr < eptr) { + if ((fdflags & O_NONBLOCK) == O_NONBLOCK) { + FD_ZERO(&wset); + FD_SET(WCC->http_sock, &wset); + if (select(WCC->http_sock + 1, NULL, &wset, NULL, NULL) == -1) { + lprintf(2, "client_write: Socket select failed (%s)\n", strerror(errno)); + return -1; + } + } -#ifdef HAVE_ZLIB - /* Perform gzip compression, if enabled and supported by client */ - if (WC->gzip_ok) { - char *compressed_data = NULL; - size_t compressed_len; - - compressed_len = ((the_len * 101) / 100) + 100; - compressed_data = malloc(compressed_len); - - if (compress_gzip((Bytef *) compressed_data, - &compressed_len, - (Bytef *) the_data, - (uLongf) the_len, Z_BEST_SPEED) == Z_OK) { - wprintf("Content-encoding: gzip\r\n"); - free(the_data); - the_data = compressed_data; - the_len = compressed_len; - } else { - free(compressed_data); - } - } -#endif /* HAVE_ZLIB */ + if ((res = write(WCC->http_sock, + ptr, + count)) == -1) { + lprintf(2, "client_write: Socket write failed (%s)\n", strerror(errno)); + return res; + } + count -= res; + ptr += res; + } - wprintf("Content-length: %d\r\n\r\n", the_len); - client_write(the_data, the_len); - free(the_data); - return; + return StrLength(WCC->WBuf); } /* - * Read data from the client socket with default timeout. + * \brief Read data from the client socket with default timeout. * (This is implemented in terms of client_read_to() and could be * justifiably moved out of sysdep.c) + * \param sock the socket fd to read from + * \param buf the buffer to write to + * \param bytes Number of bytes to read */ int client_read(int sock, char *buf, int bytes) { @@ -450,9 +366,13 @@ int client_read(int sock, char *buf, int bytes) /* - * Get a LF-terminated line of text from the client. + * \brief Get a LF-terminated line of text from the client. * (This is implemented in terms of client_read() and could be * justifiably moved out of sysdep.c) + * \param sock socket fd to get client line from + * \param buf buffer to write read data to + * \param bufsiz how many bytes to read + * \return number of bytes read??? */ int client_getln(int sock, char *buf, int bufsiz) { @@ -485,8 +405,8 @@ int client_getln(int sock, char *buf, int bufsiz) } /* - * Shut us down the regular way. - * signum is the signal we want to forward + * \brief Shut us down the regular way. + * \param signum the signal we want to forward */ pid_t current_child; void graceful_shutdown_watcher(int signum) { @@ -497,8 +417,8 @@ void graceful_shutdown_watcher(int signum) { } /* - * shut us down the regular way. - * signum is the signal we want to forward + * \brief shut us down the regular way. + * \param signum the signal we want to forward */ pid_t current_child; void graceful_shutdown(int signum) { @@ -518,6 +438,12 @@ void graceful_shutdown(int signum) { } +/* + * \brief Start running as a daemon. + * + * param do_close_stdio Only close stdio if set. + */ + /* * Start running as a daemon. */ @@ -619,12 +545,12 @@ void start_daemon(char *pid_file) } /* - * Spawn an additional worker thread into the pool. + * \brief Spawn an additional worker thread into the pool. */ void spawn_another_worker_thread() { - pthread_t SessThread; /* Thread descriptor */ - pthread_attr_t attr; /* Thread attributes */ + pthread_t SessThread; /*< Thread descriptor */ + pthread_attr_t attr; /*< Thread attributes */ int ret; lprintf(3, "Creating a new thread\n"); @@ -657,15 +583,16 @@ void spawn_another_worker_thread() const char foobuf[32]; const char *nix(void *vptr) {snprintf(foobuf, 32, "%0x", (long) vptr); return foobuf;} - /* - * Main entry point for server program. + * \brief Here's where it all begins. + * \param argc number of commandline args + * \param argv the commandline arguments */ int main(int argc, char **argv) { - pthread_t SessThread; /* Thread descriptor */ - pthread_attr_t attr; /* Thread attributes */ - int a, i; /* General-purpose variables */ + pthread_t SessThread; /*< Thread descriptor */ + pthread_attr_t attr; /*< Thread attributes */ + int a, i; /*< General-purpose variables */ char tracefile[PATH_MAX]; char ip_addr[256]="0.0.0.0"; char dirbuffer[PATH_MAX]=""; @@ -1051,8 +978,11 @@ void worker_entry(void) } /* - * print log messages + * \brief print log messages * logs to stderr if loglevel is lower than the verbosity set at startup + * \param loglevel level of the message + * \param format the printf like format string + * \param ... the strings to put into format */ int lprintf(int loglevel, const char *format, ...) { @@ -1069,7 +999,7 @@ int lprintf(int loglevel, const char *format, ...) /* - * print the actual stack frame. + * \brief print the actual stack frame. */ void wc_backtrace(void) { @@ -1091,3 +1021,4 @@ void wc_backtrace(void) #endif } +/*@}*/ diff --git a/webcit/webserver.h b/webcit/webserver.h index 47bb4f860..f190ddd94 100644 --- a/webcit/webserver.h +++ b/webcit/webserver.h @@ -8,6 +8,5 @@ extern char socket_dir[PATH_MAX]; int client_getln(int sock, char *buf, int bufsiz); int client_read(int sock, char *buf, int bytes); int client_read_to(int sock, char *buf, int bytes, int timeout); -ssize_t client_write(const void *buf, size_t count); int lprintf(int loglevel, const char *format, ...); void wc_backtrace(void); -- 2.30.2