X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fcontext_loop.c;h=1f0cf05e963c74dea87b103619cc6b92791fc031;hb=b4ad306de9560ec731db113ed509a1172209c444;hp=032c82a603399aa453a5b8d07e04af46054c54bb;hpb=435faa62a4b8f943a48cfe05593b379399e4a073;p=citadel.git diff --git a/webcit/context_loop.c b/webcit/context_loop.c index 032c82a60..1f0cf05e9 100644 --- a/webcit/context_loop.c +++ b/webcit/context_loop.c @@ -34,6 +34,30 @@ void free_attachments(struct wcsession *sess) { } +void DestroySession(struct wcsession **sessions_to_kill) +{ + close((*sessions_to_kill)->serv_sock); + close((*sessions_to_kill)->chat_sock); +// if ((*sessions_to_kill)->preferences != NULL) { +// free((*sessions_to_kill)->preferences); +// } + if ((*sessions_to_kill)->cache_fold != NULL) { + free((*sessions_to_kill)->cache_fold); + } + free_attachments((*sessions_to_kill)); + free_march_list((*sessions_to_kill)); + DeleteHash(&((*sessions_to_kill)->hash_prefs)); + DeleteHash(&((*sessions_to_kill)->IconBarSetttings)); + DeleteHash(&((*sessions_to_kill)->ServCfg)); + FreeStrBuf(&((*sessions_to_kill)->UrlFragment1)); + FreeStrBuf(&((*sessions_to_kill)->UrlFragment2)); + FreeStrBuf(&((*sessions_to_kill)->WBuf)); + FreeStrBuf(&((*sessions_to_kill)->HBuf)); + FreeStrBuf(&((*sessions_to_kill)->CLineBuf)); + free((*sessions_to_kill)); + (*sessions_to_kill) = NULL; +} + void shutdown_sessions(void) { struct wcsession *sptr; @@ -90,20 +114,10 @@ void do_housekeeping(void) while (sessions_to_kill != NULL) { lprintf(3, "Destroying session %d\n", sessions_to_kill->wc_session); pthread_mutex_lock(&sessions_to_kill->SessionMutex); - close(sessions_to_kill->serv_sock); - close(sessions_to_kill->chat_sock); - if (sessions_to_kill->preferences != NULL) { - free(sessions_to_kill->preferences); - } - if (sessions_to_kill->cache_fold != NULL) { - free(sessions_to_kill->cache_fold); - } - free_attachments(sessions_to_kill); - free_march_list(sessions_to_kill); - clear_substs(sessions_to_kill); pthread_mutex_unlock(&sessions_to_kill->SessionMutex); sptr = sessions_to_kill->next; - free(sessions_to_kill); + + DestroySession(&sessions_to_kill); sessions_to_kill = sptr; --num_sessions; } @@ -157,40 +171,52 @@ int GenerateSessionID(void) /* * Collapse multiple cookies on one line */ -int req_gets(int sock, char *buf, char *hold) -{ - int a, b; - - if (IsEmptyStr(hold)) { - strcpy(buf, ""); - a = client_getln(sock, buf, SIZ); - if (a<1) return(-1); - } else { - safestrncpy(buf, hold, SIZ); - } - strcpy(hold, ""); - - if (!strncasecmp(buf, "Cookie: ", 8)) { - int len; - len = strlen(buf); - for (a = 0; a < len; ++a) - if (buf[a] == ';') { - // we don't refresh len, because of we - // only exit from here. - sprintf(hold, "Cookie: %s", &buf[a + 1]); - buf[a] = 0; - b = 8; - while (isspace(hold[b])) - b++; - - memmove(&hold[8], &hold[b], len - b + 1); - return(0); - } - } +////int req_gets(int *sock, char *buf, char *hold, size_t hlen) +////{ +//// int a, b; +//// +//// if (IsEmptyStr(hold)) { +//// strcpy(buf, ""); +//// a = client_getln(sock, buf, SIZ); +//// if (a<1) return(-1); +//// } else { +//// safestrncpy(buf, hold, SIZ); +//// } +//// strcpy(hold, ""); +//// +//// if (!strncasecmp(buf, "Cookie: ", 8)) { +//// int len; +//// len = strlen(buf); +//// for (a = 0; a < len; ++a) +//// if (buf[a] == ';') { +//// // we don't refresh len, because of we +//// // only exit from here. +//// snprintf(hold, hlen, "Cookie: %s", &buf[a + 1]); +//// buf[a] = 0; +//// b = 8; +//// while (isspace(hold[b])) +//// b++; +//// +//// memmove(&hold[8], &hold[b], len - b + 1); +//// return(0); +//// } +//// } +//// +//// return(0); +////} + - return(0); +/* + * Collapse multiple cookies on one line + */ +int ReqGetStrBuf(int *sock, StrBuf *Target, StrBuf *buf) +{ + + return ClientGetLine(sock, Target, buf); } + + /* * lingering_close() a`la Apache. see * http://www.apache.org/docs/misc/fin_wait_2.html for rationale @@ -235,12 +261,12 @@ int lingering_close(int fd) * * \param http_cmd The HTTP request to check */ -int is_bogus(char *http_cmd) { - char *url; +int is_bogus(StrBuf *http_cmd) { + const char *url; int i, max; - url = strstr(http_cmd, " "); - if (url == NULL) return(1); + url = ChrPtr(http_cmd); + if (IsEmptyStr(url)) return(1); ++url; char *bogus_prefixes[] = { @@ -263,6 +289,7 @@ int is_bogus(char *http_cmd) { } +const char *nix(void *vptr) {return ChrPtr( (StrBuf*)vptr);} /** * \brief handle one request @@ -277,12 +304,9 @@ int is_bogus(char *http_cmd) { * transaction. * \param sock the socket we will put our answer to */ -void context_loop(int sock) +void context_loop(int *sock) { - struct httprequest *req = NULL; - struct httprequest *last = NULL; - struct httprequest *hptr; - char buf[SIZ], hold[SIZ]; + const char *buf; int desired_session = 0; int got_cookie = 0; int gzip_ok = 0; @@ -290,9 +314,15 @@ void context_loop(int sock) char httpauth_string[1024]; char httpauth_user[1024]; char httpauth_pass[1024]; - char accept_language[256]; char *ptr = NULL; int session_is_new = 0; + int nLine = 0; + int LineLen; + void *vLine; + StrBuf *Buf, *Line, *LastLine, *HeaderName, *ReqLine, *ReqType, *HTTPVersion; + StrBuf *accept_language = NULL; + const char *pch, *pchs, *pche; + HashList *HTTPHeaders; strcpy(httpauth_string, ""); strcpy(httpauth_user, DEFAULT_HTTPAUTH_USER); @@ -301,104 +331,161 @@ void context_loop(int sock) /** * Find out what it is that the web browser is asking for */ - memset(hold, 0, sizeof(hold)); + HeaderName = NewStrBuf(); + Buf = NewStrBuf(); + LastLine = NULL; + HTTPHeaders = NewHash(1, NULL); + /** + * Read in the request + */ do { - if (req_gets(sock, buf, hold) < 0) return; - - /** - * Can we compress? - */ - if (!strncasecmp(buf, "Accept-encoding:", 16)) { - if (strstr(&buf[16], "gzip")) { - gzip_ok = 1; - } - } + nLine ++; + Line = NewStrBuf(); + if (ReqGetStrBuf(sock, Line, Buf) < 0) return; - /** - * Browser-based sessions use cookies for session authentication - */ - if (!strncasecmp(buf, "Cookie: webcit=", 15)) { - cookie_to_stuff(&buf[15], &desired_session, - NULL, 0, NULL, 0, NULL, 0); - got_cookie = 1; + LineLen = StrLength(Line); + + if (nLine == 1) { + ReqLine = Line; + continue; + } + if (LineLen == 0) { + FreeStrBuf(&Line); + continue; } - /** - * GroupDAV-based sessions use HTTP authentication - */ - if (!strncasecmp(buf, "Authorization: Basic ", 21)) { - CtdlDecodeBase64(httpauth_string, &buf[21], strlen(&buf[21])); - extract_token(httpauth_user, httpauth_string, 0, ':', sizeof httpauth_user); - extract_token(httpauth_pass, httpauth_string, 1, ':', sizeof httpauth_pass); + /** Do we need to Unfold? */ + if ((LastLine != NULL) && + (isspace(*ChrPtr(Line)))) { + pch = pchs = ChrPtr(Line); + pche = pchs + StrLength(Line); + while (isspace(pch) && (pch < pche)) + pch ++; + StrBufCutLeft(Line, pch - pchs); + StrBufAppendBuf(LastLine, Line, 0); + FreeStrBuf(&Line); + continue; } - if (!strncasecmp(buf, "If-Modified-Since: ", 19)) { - if_modified_since = httpdate_to_timestamp(&buf[19]); + StrBufExtract_token(HeaderName, Line, 0, ':'); + //// TODO: filter bad chars! + + pchs = ChrPtr(Line); + pch = pchs + StrLength(HeaderName) + 1; + pche = pchs + StrLength(Line); + while (isspace(*pch) && (pch < pche)) + pch ++; + StrBufCutLeft(Line, pch - pchs); + + StrBufUpCase(HeaderName); + Put(HTTPHeaders, SKEY(HeaderName), Line, HFreeStrBuf); + LastLine = Line; + } while (LineLen > 0); + FreeStrBuf(&HeaderName); + +//// dbg_PrintHash(HTTPHeaders, nix, NULL); + + + /** + * Can we compress? + */ + if (GetHash(HTTPHeaders, HKEY("ACCEPT-ENCODING"), &vLine) && + (vLine != NULL)) { + buf = ChrPtr((StrBuf*)vLine); + if (strstr(&buf[16], "gzip")) { + gzip_ok = 1; } + } - if (!strncasecmp(buf, "Accept-Language: ", 17)) { - safestrncpy(accept_language, &buf[17], sizeof accept_language); + /** + * Browser-based sessions use cookies for session authentication + */ + if (GetHash(HTTPHeaders, HKEY("COOKIE"), &vLine) && + (vLine != NULL)) { + cookie_to_stuff(vLine, &desired_session, + NULL, 0, NULL, 0, NULL, 0); + got_cookie = 1; + } + + /** + * GroupDAV-based sessions use HTTP authentication + */ + if (GetHash(HTTPHeaders, HKEY("AUTHORIZATION"), &vLine) && + (vLine != NULL)) { + Line = (StrBuf*)vLine; + if (strncasecmp(ChrPtr(Line), "Basic ", 6)) { + StrBufCutLeft(Line, 6); + CtdlDecodeBase64(httpauth_string, ChrPtr(Line), StrLength(Line)); + extract_token(httpauth_user, httpauth_string, 0, ':', sizeof httpauth_user); + extract_token(httpauth_pass, httpauth_string, 1, ':', sizeof httpauth_pass); } + else + lprintf(1, "Authentication sheme not supported! [%s]\n", ChrPtr(Line)); + } - /** - * Read in the request - */ - hptr = (struct httprequest *) - malloc(sizeof(struct httprequest)); - if (req == NULL) - req = hptr; - else - last->next = hptr; - hptr->next = NULL; - last = hptr; + if (GetHash(HTTPHeaders, HKEY("IF-MODIFIED-SINCE"), &vLine) && + (vLine != NULL)) { + if_modified_since = httpdate_to_timestamp((StrBuf*)vLine); + } - safestrncpy(hptr->line, buf, sizeof hptr->line); + if (GetHash(HTTPHeaders, HKEY("ACCEPT-LANGUAGE"), &vLine) && + (vLine != NULL)) { + accept_language = (StrBuf*) vLine; + } - } while (!IsEmptyStr(buf)); /** * If the request is prefixed by "/webcit" then chop that off. This * allows a front end web server to forward all /webcit requests to us * while still using the same web server port for other things. */ - - ptr = strstr(req->line, " /webcit "); /*< Handle "/webcit" */ - if (ptr != NULL) { - strcpy(ptr+2, ptr+8); - } - ptr = strstr(req->line, " /webcit"); /*< Handle "/webcit/" */ - if (ptr != NULL) { - strcpy(ptr+1, ptr+8); + ReqType = NewStrBuf(); + HTTPVersion = NewStrBuf(); + StrBufExtract_token(HTTPVersion, ReqLine, 2, ' '); + StrBufExtract_token(ReqType, ReqLine, 0, ' '); + StrBufCutLeft(ReqLine, StrLength(ReqType) + 1); + StrBufCutRight(ReqLine, StrLength(HTTPVersion) + 1); + + if ((StrLength(ReqLine) >= 8) && + (ptr = strstr(ChrPtr(ReqLine), "/webcit/"), /*< Handle "/webcit/" */ + (ptr != NULL))) { + StrBufCutLeft(ReqLine, 7); } /** Begin parsing the request. */ - - safestrncpy(buf, req->line, sizeof buf); - lprintf(5, "HTTP: %s\n", buf); +#ifdef TECH_PREVIEW + if ((strncmp(ChrPtr(ReqLine), "/sslg", 5) != 0) && + (strncmp(ChrPtr(ReqLine), "/static/", 8) != 0) && + (strncmp(ChrPtr(ReqLine), "/wholist_section", 16) != 0)) { +#endif + lprintf(5, "HTTP: %s %s %s\n", ChrPtr(ReqType), ChrPtr(ReqLine), ChrPtr(HTTPVersion)); +#ifdef TECH_PREVIEW + } +#endif /** Check for bogus requests */ - if (is_bogus(buf)) { - strcpy(req->line, "GET /404 HTTP/1.1"); - strcpy(buf, "GET /404 HTTP/1.1"); + if ((StrLength(HTTPVersion) == 0) || + (StrLength(ReqType) == 0) || + is_bogus(ReqLine)) { + StrBufPlain(ReqLine, HKEY("/404 HTTP/1.1")); + StrBufPlain(ReqType, HKEY("GET")); } - - /** - * Strip out the method, leaving the URL up front... - */ - remove_token(buf, 0, ' '); - if (buf[1]==' ') buf[1]=0; + FreeStrBuf(&HTTPVersion); /** * While we're at it, gracefully handle requests for the * robots.txt and favicon.ico files. */ - if (!strncasecmp(buf, "/robots.txt", 11)) { - strcpy(req->line, "GET /static/robots.txt" - "?force_close_session=yes HTTP/1.1"); + if (!strncasecmp(ChrPtr(ReqLine), "/robots.txt", 11)) { + StrBufPlain(ReqLine, + HKEY("/static/robots.txt" + "?force_close_session=yes HTTP/1.1")); + StrBufPlain(ReqType, HKEY("GET")); } - else if (!strncasecmp(buf, "/favicon.ico", 12)) { - strcpy(req->line, "GET /static/favicon.ico"); + else if (!strncasecmp(ChrPtr(ReqLine), "/favicon.ico", 12)) { + StrBufPlain(ReqLine, HKEY("/static/favicon.ico")); + StrBufPlain(ReqType, HKEY("GET")); } /** @@ -407,17 +494,18 @@ void context_loop(int sock) * force the session to close because cookies are * probably disabled on the client browser. */ - else if ( (strcmp(buf, "/")) - && (strncasecmp(buf, "/listsub", 8)) - && (strncasecmp(buf, "/freebusy", 9)) - && (strncasecmp(buf, "/do_logout", 10)) - && (strncasecmp(buf, "/groupdav", 9)) - && (strncasecmp(buf, "/static", 7)) - && (strncasecmp(buf, "/rss", 4)) - && (strncasecmp(buf, "/404", 4)) + else if ( (StrLength(ReqLine) > 1 ) + && (strncasecmp(ChrPtr(ReqLine), "/listsub", 8)) + && (strncasecmp(ChrPtr(ReqLine), "/freebusy", 9)) + && (strncasecmp(ChrPtr(ReqLine), "/do_logout", 10)) + && (strncasecmp(ChrPtr(ReqLine), "/groupdav", 9)) + && (strncasecmp(ChrPtr(ReqLine), "/static", 7)) + && (strncasecmp(ChrPtr(ReqLine), "/rss", 4)) + && (strncasecmp(ChrPtr(ReqLine), "/404", 4)) && (got_cookie == 0)) { - strcpy(req->line, "GET /static/nocookies.html" - "?force_close_session=yes HTTP/1.1"); + StrBufPlain(ReqLine, + HKEY("/static/nocookies.html" + "?force_close_session=yes")); } /** @@ -471,10 +559,16 @@ void context_loop(int sock) strcpy(TheSession->httpauth_user, httpauth_user); strcpy(TheSession->httpauth_pass, httpauth_pass); + TheSession->hash_prefs = NewHash(1,NULL); /* Get a hash table for the user preferences */ pthread_mutex_init(&TheSession->SessionMutex, NULL); pthread_mutex_lock(&SessionListMutex); + TheSession->urlstrings = NULL; + TheSession->vars = NULL; TheSession->nonce = rand(); + TheSession->WBuf = NULL; + TheSession->CLineBuf = NewStrBuf(); TheSession->next = SessionList; + TheSession->is_mobile = -1; SessionList = TheSession; pthread_mutex_unlock(&SessionListMutex); session_is_new = 1; @@ -490,7 +584,10 @@ void context_loop(int sock) */ pthread_mutex_lock(&TheSession->SessionMutex); /* bind */ pthread_setspecific(MyConKey, (void *)TheSession); - TheSession->http_sock = sock; + + TheSession->urlstrings = NewHash(1,NULL); + TheSession->vars = NewHash(1,NULL); + TheSession->http_sock = *sock; TheSession->lastreq = time(NULL); /* log */ TheSession->gzip_ok = gzip_ok; #ifdef ENABLE_NLS @@ -499,22 +596,41 @@ void context_loop(int sock) } go_selected_language(); /* set locale */ #endif - session_loop(req); /* do transaction */ + session_loop(HTTPHeaders, ReqLine, ReqType, Buf); /* do transaction */ #ifdef ENABLE_NLS stop_selected_language(); /* unset locale */ #endif + DeleteHash(&TheSession->urlstrings); + DeleteHash(&TheSession->vars); + FreeStrBuf(&TheSession->WBuf); + FreeStrBuf(&TheSession->HBuf); + + pthread_mutex_unlock(&TheSession->SessionMutex); /* unbind */ /* Free the request buffer */ - while (req != NULL) { - hptr = req->next; - free(req); - req = hptr; - } - + DeleteHash(&HTTPHeaders); + FreeStrBuf(&ReqLine); + FreeStrBuf(&ReqType); + FreeStrBuf(&Buf); /* * Free up any session-local substitution variables which * were set during this transaction */ - clear_local_substs(); + + +} + +void tmpl_nonce(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) +{ + struct wcsession *WCC = WC; + StrBufAppendPrintf(Target, "%ld", + (WCC != NULL)? WCC->nonce:0); +} + +void +InitModule_CONTEXT +(void) +{ + RegisterNamespace("NONCE", 0, 0, tmpl_nonce, 0); }