Back to index

webcit  8.12-dfsg
Functions | Variables
context_loop.c File Reference
#include "webcit.h"
#include "webserver.h"
#include "modules_init.h"

Go to the source code of this file.

Functions

void session_loop (void)
void spawn_another_worker_thread (void)
void DestroyHttpHeaderHandler (void *V)
void shutdown_sessions (void)
void do_housekeeping (void)
void check_thread_pool_size (void)
void housekeeping_loop (void)
int GenerateSessionID (void)
wcsessionFindSession (wcsession **wclist, ParsedHttpHdrs *Hdr, pthread_mutex_t *ListMutex)
wcsessionCreateSession (int Lockable, int Static, wcsession **wclist, ParsedHttpHdrs *Hdr, pthread_mutex_t *ListMutex)
void do_404 (void)
int ReadHttpSubject (ParsedHttpHdrs *Hdr, StrBuf *Line, StrBuf *Buf)
int AnalyseHeaders (ParsedHttpHdrs *Hdr)
int ReadHTTPRequest (ParsedHttpHdrs *Hdr)
void OverrideRequest (ParsedHttpHdrs *Hdr, const char *Line, long len)
void context_loop (ParsedHttpHdrs *Hdr)
void tmplput_nonce (StrBuf *Target, WCTemplputParams *TP)
void tmplput_current_user (StrBuf *Target, WCTemplputParams *TP)
void Header_HandleContentLength (StrBuf *Line, ParsedHttpHdrs *hdr)
void Header_HandleContentType (StrBuf *Line, ParsedHttpHdrs *hdr)
void Header_HandleHost (StrBuf *Line, ParsedHttpHdrs *hdr)
void Header_HandleXFFHost (StrBuf *Line, ParsedHttpHdrs *hdr)
void Header_HandleXFF (StrBuf *Line, ParsedHttpHdrs *hdr)
void Header_HandleIfModSince (StrBuf *Line, ParsedHttpHdrs *hdr)
void Header_HandleAcceptEncoding (StrBuf *Line, ParsedHttpHdrs *hdr)
void ServerStartModule_CONTEXT (void)
void ServerShutdownModule_CONTEXT (void)
void RegisterHeaderHandler (const char *Name, long Len, Header_Evaluator F)
void InitModule_CONTEXT (void)
void HttpNewModule_CONTEXT (ParsedHttpHdrs *httpreq)
void HttpDetachModule_CONTEXT (ParsedHttpHdrs *httpreq)
void HttpDestroyModule_CONTEXT (ParsedHttpHdrs *httpreq)

Variables

pthread_mutex_t SessionListMutex
wcsessionSessionList = NULL
pthread_key_t MyConKey
HashList * HttpReqTypes = NULL
HashList * HttpHeaderHandler = NULL
HashList * HandlerHash
int num_threads_existing = 1
int num_threads_executing = 1
const char * ReqStrs [eNONE]

Function Documentation

Definition at line 351 of file context_loop.c.

{
       OneHttpHeader *pHdr;
       void *vHdr;
       long HKLen;
       const char *HashKey;
       HashPos *at = GetNewHashPos(Hdr->HTTPHeaders, 0);
       
       while (GetNextHashPos(Hdr->HTTPHeaders, at, &HKLen, &HashKey, &vHdr) && 
              (vHdr != NULL)) {
              pHdr = (OneHttpHeader *)vHdr;
              if (pHdr->HaveEvaluator)
                     pHdr->H(pHdr->Val, Hdr);

       }
       DeleteHashPos(&at);
       return 0;
}

Here is the caller graph for this function:

void check_thread_pool_size ( void  )

Definition at line 108 of file context_loop.c.

{
       if (time_to_die) return;           /* don't expand the thread pool during shutdown */

       begin_critical_section(S_SPAWNER); /* only one of these should run at a time */
       if (
              (num_threads_executing >= num_threads_existing)
              && (num_threads_existing < MAX_WORKER_THREADS)
       ) {
              syslog(3, "%d of %d threads are executing.  Adding another worker thread.",
                     num_threads_executing,
                     num_threads_existing
              );
              spawn_another_worker_thread();
       }
       end_critical_section(S_SPAWNER);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void context_loop ( ParsedHttpHdrs Hdr)

Definition at line 484 of file context_loop.c.

{
       int isbogus = 0;
       wcsession *TheSession;
       struct timeval tx_start;
       struct timeval tx_finish;
       int session_may_be_reused = 1;
       
       gettimeofday(&tx_start, NULL);            /* start a stopwatch for performance timing */

       /*
        * Find out what it is that the web browser is asking for
        */
       isbogus = ReadHTTPRequest(Hdr);

       Hdr->HR.dav_depth = 32767; /* TODO: find a general way to have non-0 defaults */

       if (!isbogus) {
              isbogus = AnalyseHeaders(Hdr);
       }

       if (   (isbogus)
              || ((Hdr->HR.Handler != NULL)
              && ((Hdr->HR.Handler->Flags & BOGUS) != 0))
       ) {
              wcsession *Bogus;
              Bogus = CreateSession(0, 1, NULL, Hdr, NULL);
              do_404();
              syslog(9, "HTTP: 404 [%ld.%06ld] %s %s",
                     ((tx_finish.tv_sec*1000000 + tx_finish.tv_usec) - (tx_start.tv_sec*1000000 + tx_start.tv_usec)) / 1000000,
                     ((tx_finish.tv_sec*1000000 + tx_finish.tv_usec) - (tx_start.tv_sec*1000000 + tx_start.tv_usec)) % 1000000,
                     ReqStrs[Hdr->HR.eReqType],
                     ChrPtr(Hdr->this_page)
                     );
              session_detach_modules(Bogus);
              session_destroy_modules(&Bogus);
              return;
       }

       if ((Hdr->HR.Handler != NULL) && ((Hdr->HR.Handler->Flags & ISSTATIC) != 0))
       {
              wcsession *Static;
              Static = CreateSession(0, 1, NULL, Hdr, NULL);
              
              Hdr->HR.Handler->F();

              /* How long did this transaction take? */
              gettimeofday(&tx_finish, NULL);
              
              syslog(9, "HTTP: 200 [%ld.%06ld] %s %s",
                     ((tx_finish.tv_sec*1000000 + tx_finish.tv_usec) - (tx_start.tv_sec*1000000 + tx_start.tv_usec)) / 1000000,
                     ((tx_finish.tv_sec*1000000 + tx_finish.tv_usec) - (tx_start.tv_sec*1000000 + tx_start.tv_usec)) % 1000000,
                     ReqStrs[Hdr->HR.eReqType],
                     ChrPtr(Hdr->this_page)
              );
              session_detach_modules(Static);
              session_destroy_modules(&Static);
              return;
       }

       if (Hdr->HR.got_auth == AUTH_BASIC) {
              CheckAuthBasic(Hdr);
       }

       if (Hdr->HR.got_auth) {
              session_may_be_reused = 0;
       }

       /*
        * See if there's an existing session open with any of:
        * - The desired Session ID
        * - A matching http-auth username and password
        * - An unbound session flagged as reusable
        */
       TheSession = FindSession(&SessionList, Hdr, &SessionListMutex);

       /*
        * If there were no qualifying sessions, then create a new one.
        */
       if (TheSession == NULL) {
              TheSession = CreateSession(1, 0, &SessionList, Hdr, &SessionListMutex);
       }

       /*
        * Reject transactions which require http-auth, if http-auth was not provided
        */
       if (   (StrLength(Hdr->c_username) == 0)
              && (!Hdr->HR.DontNeedAuth)
              && (Hdr->HR.Handler != NULL)
              && ((XHTTP_COMMANDS & Hdr->HR.Handler->Flags) == XHTTP_COMMANDS)
       ) {
              syslog(LOG_DEBUG, "http-auth required but not provided");
              OverrideRequest(Hdr, HKEY("GET /401 HTTP/1.0"));
              Hdr->HR.prohibit_caching = 1;                           
       }

       /*
        * A future improvement might be to check the session integrity
        * at this point before continuing.
        */

       /*
        * Bind to the session and perform the transaction
        */
       CtdlLogResult(pthread_mutex_lock(&TheSession->SessionMutex));
       pthread_setspecific(MyConKey, (void *)TheSession);
       
       TheSession->inuse = 1;                                  /* mark the session as bound */
       TheSession->lastreq = time(NULL);                /* log */
       TheSession->Hdr = Hdr;

       /*
        * If a language was requested via a cookie, select that language now.
        */
       if (StrLength(Hdr->c_language) > 0) {
              syslog(LOG_DEBUG, "Session cookie requests language '%s'", ChrPtr(Hdr->c_language));
              set_selected_language(ChrPtr(Hdr->c_language));
              go_selected_language();
       }

       /*
        * do the transaction
        */
       session_attach_modules(TheSession);
       session_loop();

       /* How long did this transaction take? */
       gettimeofday(&tx_finish, NULL);

       syslog(9, "HTTP: 200 [%ld.%06ld] %s %s",
              ((tx_finish.tv_sec*1000000 + tx_finish.tv_usec) - (tx_start.tv_sec*1000000 + tx_start.tv_usec)) / 1000000,
              ((tx_finish.tv_sec*1000000 + tx_finish.tv_usec) - (tx_start.tv_sec*1000000 + tx_start.tv_usec)) % 1000000,
              ReqStrs[Hdr->HR.eReqType],
              ChrPtr(Hdr->this_page)
       );

       session_detach_modules(TheSession);

       /* If *this* very transaction did not explicitly specify a session cookie,
        * and it did not log in, we want to flag the session as a candidate for
        * re-use by the next unbound client that comes along.  This keeps our session
        * table from getting bombarded with new sessions when, for example, a web
        * spider crawls the site without using cookies.
        */
       if ((session_may_be_reused) && (!WC->logged_in)) {
              WC->wc_session = 0;                /* flag as available for re-use */
              TheSession->selected_language = 0; /* clear any non-default language setting */
       }

       TheSession->Hdr = NULL;
       TheSession->inuse = 0;                                  /* mark the session as unbound */
       CtdlLogResult(pthread_mutex_unlock(&TheSession->SessionMutex));
}

Here is the call graph for this function:

Here is the caller graph for this function:

wcsession* CreateSession ( int  Lockable,
int  Static,
wcsession **  wclist,
ParsedHttpHdrs Hdr,
pthread_mutex_t *  ListMutex 
)

Definition at line 204 of file context_loop.c.

{
       wcsession *TheSession;
       TheSession = (wcsession *) malloc(sizeof(wcsession));
       memset(TheSession, 0, sizeof(wcsession));
       TheSession->Hdr = Hdr;
       TheSession->serv_sock = (-1);

       pthread_setspecific(MyConKey, (void *)TheSession);
       
       /* If we're recreating a session that expired, it's best to give it the same
        * session number that it had before.  The client browser ought to pick up
        * the new session number and start using it, but in some rare situations it
        * doesn't, and that's a Bad Thing because it causes lots of spurious sessions
        * to get created.
        */    
       if (Hdr->HR.desired_session == 0) {
              TheSession->wc_session = GenerateSessionID();
              syslog(3, "Created new session %d", TheSession->wc_session);
       }
       else {
              TheSession->wc_session = Hdr->HR.desired_session;
              syslog(3, "Re-created session %d", TheSession->wc_session);
       }
       Hdr->HR.Static = Static;
       session_new_modules(TheSession);

       if (Lockable) {
              pthread_mutex_init(&TheSession->SessionMutex, NULL);

              if (ListMutex != NULL)
                     CtdlLogResult(pthread_mutex_lock(ListMutex));

              if (wclist != NULL) {
                     TheSession->nonce = rand();
                     TheSession->next = *wclist;
                     *wclist = TheSession;
              }
              if (ListMutex != NULL)
                     CtdlLogResult(pthread_mutex_unlock(ListMutex));
       }
       return TheSession;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void DestroyHttpHeaderHandler ( void *  V)

Definition at line 40 of file context_loop.c.

{
       OneHttpHeader *pHdr;
       pHdr = (OneHttpHeader*) V;
       FreeStrBuf(&pHdr->Val);
       free(pHdr);
}

Here is the caller graph for this function:

void do_404 ( void  )

Definition at line 250 of file context_loop.c.

{
       hprintf("HTTP/1.1 404 Not found\r\n");
       hprintf("Content-Type: text/plain\r\n");
       wc_printf("Not found\r\n");
       end_burst();
}

Here is the call graph for this function:

Here is the caller graph for this function:

void do_housekeeping ( void  )

Definition at line 57 of file context_loop.c.

{
       wcsession *sptr, *ss;
       wcsession *sessions_to_kill = NULL;

       /*
        * Lock the session list, moving any candidates for euthanasia into
        * a separate list.
        */
       CtdlLogResult(pthread_mutex_lock(&SessionListMutex));
       for (sptr = SessionList; sptr != NULL; sptr = sptr->next) {

              /* Kill idle sessions */
              if ((time(NULL) - (sptr->lastreq)) > (time_t) WEBCIT_TIMEOUT) {
                     syslog(3, "Timeout session %d", sptr->wc_session);
                     sptr->killthis = 1;
              }

              /* Remove sessions flagged for kill */
              if (sptr->killthis) {

                     /* remove session from linked list */
                     if (sptr == SessionList) {
                            SessionList = SessionList->next;
                     }
                     else for (ss=SessionList;ss!=NULL;ss=ss->next) {
                            if (ss->next == sptr) {
                                   ss->next = ss->next->next;
                            }
                     }

                     sptr->next = sessions_to_kill;
                     sessions_to_kill = sptr;
              }
       }
       CtdlLogResult(pthread_mutex_unlock(&SessionListMutex));

       /*
        * Now free up and destroy the culled sessions.
        */
       while (sessions_to_kill != NULL) {
              syslog(3, "Destroying session %d", sessions_to_kill->wc_session);
              sptr = sessions_to_kill->next;
              session_destroy_modules(&sessions_to_kill);
              sessions_to_kill = sptr;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

wcsession* FindSession ( wcsession **  wclist,
ParsedHttpHdrs Hdr,
pthread_mutex_t *  ListMutex 
)

Definition at line 155 of file context_loop.c.

{
       wcsession *sptr = NULL;
       wcsession *TheSession = NULL;      
       
       if (Hdr->HR.got_auth == AUTH_BASIC) {
              GetAuthBasic(Hdr);
       }

       CtdlLogResult(pthread_mutex_lock(ListMutex));
       for (sptr = *wclist; ((sptr != NULL) && (TheSession == NULL)); sptr = sptr->next) {
              
              /* If HTTP-AUTH, look for a session with matching credentials */
              switch (Hdr->HR.got_auth)
              {
              case AUTH_BASIC:
                     if (   (!strcasecmp(ChrPtr(Hdr->c_username), ChrPtr(sptr->wc_username)))
                            && (!strcasecmp(ChrPtr(Hdr->c_password), ChrPtr(sptr->wc_password)))
                            && (sptr->killthis == 0)
                     ) {
                            syslog(LOG_DEBUG, "Matched a session with the same http-auth");
                            TheSession = sptr;
                     }
                     break;
              case AUTH_COOKIE:
                     /* If cookie-session, look for a session with matching session ID */
                     if (   (Hdr->HR.desired_session != 0)
                            && (sptr->wc_session == Hdr->HR.desired_session)
                     ) {
                            syslog(LOG_DEBUG, "Matched a session with the same cookie");
                            TheSession = sptr;
                     }
                     break;                    
              case NO_AUTH:
                     /* Any unbound session is a candidate */
                     if ( (sptr->wc_session == 0) && (sptr->inuse == 0) ) {
                            syslog(LOG_DEBUG, "Reusing an unbound session");
                            TheSession = sptr;
                     }
                     break;
              }
       }
       CtdlLogResult(pthread_mutex_unlock(ListMutex));
       if (TheSession == NULL) {
              syslog(LOG_DEBUG, "No existing session was matched");
       }
       return TheSession;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int GenerateSessionID ( void  )

Definition at line 144 of file context_loop.c.

{
       static int seq = (-1);

       if (seq < 0) {
              seq = (int) time(NULL);
       }
              
       return ++seq;
}

Here is the caller graph for this function:

void Header_HandleAcceptEncoding ( StrBuf *  Line,
ParsedHttpHdrs hdr 
)

Definition at line 700 of file context_loop.c.

{
       /*
        * Can we compress?
        */
       if (strstr(&ChrPtr(Line)[16], "gzip")) {
              hdr->HR.gzip_ok = 1;
       }
}

Here is the caller graph for this function:

void Header_HandleContentLength ( StrBuf *  Line,
ParsedHttpHdrs hdr 
)

Definition at line 650 of file context_loop.c.

{
       hdr->HR.ContentLength = StrToi(Line);
}

Here is the caller graph for this function:

void Header_HandleContentType ( StrBuf *  Line,
ParsedHttpHdrs hdr 
)

Definition at line 655 of file context_loop.c.

{
       hdr->HR.ContentType = Line;
}

Here is the caller graph for this function:

void Header_HandleHost ( StrBuf *  Line,
ParsedHttpHdrs hdr 
)

Definition at line 661 of file context_loop.c.

{
       if (hdr->HostHeader != NULL) {
              FreeStrBuf(&hdr->HostHeader);
       }
       hdr->HostHeader = NewStrBuf();
       StrBufAppendPrintf(hdr->HostHeader, "%s://", (is_https ? "https" : "http") );
       StrBufAppendBuf(hdr->HostHeader, Line, 0);
}

Here is the caller graph for this function:

void Header_HandleIfModSince ( StrBuf *  Line,
ParsedHttpHdrs hdr 
)

Definition at line 695 of file context_loop.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void Header_HandleXFF ( StrBuf *  Line,
ParsedHttpHdrs hdr 
)

Definition at line 685 of file context_loop.c.

{
       hdr->HR.browser_host = Line;

       while (StrBufNum_tokens(hdr->HR.browser_host, ',') > 1) {
              StrBufRemove_token(hdr->HR.browser_host, 0, ',');
       }
       StrBufTrim(hdr->HR.browser_host);
}

Here is the caller graph for this function:

void Header_HandleXFFHost ( StrBuf *  Line,
ParsedHttpHdrs hdr 
)

Definition at line 671 of file context_loop.c.

{
       if (!follow_xff) return;

       if (hdr->HostHeader != NULL) {
              FreeStrBuf(&hdr->HostHeader);
       }

       hdr->HostHeader = NewStrBuf();
       StrBufAppendPrintf(hdr->HostHeader, "http://");  /* this is naive; do something about it */
       StrBufAppendBuf(hdr->HostHeader, Line, 0);
}

Here is the caller graph for this function:

void housekeeping_loop ( void  )

Definition at line 130 of file context_loop.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 841 of file context_loop.c.

{
       FreeStrBuf(&httpreq->this_page);
       FreeStrBuf(&httpreq->PlainArgs);
       FreeStrBuf(&httpreq->this_page);
       FreeStrBuf(&httpreq->PlainArgs);
       FreeStrBuf(&httpreq->HostHeader);
       DeleteHash(&httpreq->HTTPHeaders);

}

Here is the caller graph for this function:

Definition at line 829 of file context_loop.c.

{
       FlushStrBuf(httpreq->PlainArgs);
       FlushStrBuf(httpreq->HostHeader);
       FlushStrBuf(httpreq->this_page);
       FlushStrBuf(httpreq->PlainArgs);
       DeleteHash(&httpreq->HTTPHeaders);
       memset(&httpreq->HR, 0, sizeof(HdrRefs));
}

Here is the caller graph for this function:

Definition at line 821 of file context_loop.c.

{
       httpreq->PlainArgs = NewStrBufPlain(NULL, SIZ);
       httpreq->this_page = NewStrBufPlain(NULL, SIZ);
}

Here is the caller graph for this function:

void InitModule_CONTEXT ( void  )

Definition at line 791 of file context_loop.c.

{
       RegisterHeaderHandler(HKEY("CONTENT-LENGTH"), Header_HandleContentLength);
       RegisterHeaderHandler(HKEY("CONTENT-TYPE"), Header_HandleContentType);
       RegisterHeaderHandler(HKEY("X-FORWARDED-HOST"), Header_HandleXFFHost); /* Apache way... */
       RegisterHeaderHandler(HKEY("X-REAL-IP"), Header_HandleXFFHost);        /* NGinX way... */
       RegisterHeaderHandler(HKEY("HOST"), Header_HandleHost);
       RegisterHeaderHandler(HKEY("X-FORWARDED-FOR"), Header_HandleXFF);
       RegisterHeaderHandler(HKEY("ACCEPT-ENCODING"), Header_HandleAcceptEncoding);
       RegisterHeaderHandler(HKEY("IF-MODIFIED-SINCE"), Header_HandleIfModSince);

       RegisterNamespace("CURRENT_USER", 0, 1, tmplput_current_user, NULL, CTX_NONE);
       RegisterNamespace("NONCE", 0, 0, tmplput_nonce, NULL, 0);

       WebcitAddUrlHandler(HKEY("404"), "", 0, do_404, ANONYMOUS|COOKIEUNNEEDED);
/*
 * Look for commonly-found probes of malware such as worms, viruses, trojans, and Microsoft Office.
 * Short-circuit these requests so we don't have to send them through the full processing loop.
 */
       WebcitAddUrlHandler(HKEY("scripts"), "", 0, do_404, ANONYMOUS|BOGUS);        /* /root.exe - Worms and trojans and viruses, oh my! */
       WebcitAddUrlHandler(HKEY("c"), "", 0, do_404, ANONYMOUS|BOGUS);              /* /winnt */
       WebcitAddUrlHandler(HKEY("MSADC"), "", 0, do_404, ANONYMOUS|BOGUS);
       WebcitAddUrlHandler(HKEY("_vti"), "", 0, do_404, ANONYMOUS|BOGUS);           /* Broken Microsoft DAV implementation */
       WebcitAddUrlHandler(HKEY("MSOffice"), "", 0, do_404, ANONYMOUS|BOGUS);              /* Stoopid MSOffice thinks everyone is IIS */
       WebcitAddUrlHandler(HKEY("nonexistenshit"), "", 0, do_404, ANONYMOUS|BOGUS); /* Exploit found in the wild January 2009 */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void OverrideRequest ( ParsedHttpHdrs Hdr,
const char *  Line,
long  len 
)

Definition at line 455 of file context_loop.c.

{
       StrBuf *Buf = NewStrBuf();

       if (Hdr->HR.ReqLine != NULL) {
              FlushStrBuf(Hdr->HR.ReqLine);
              StrBufPlain(Hdr->HR.ReqLine, Line, len);
       }
       else {
              Hdr->HR.ReqLine = NewStrBufPlain(Line, len);
       }
       ReadHttpSubject(Hdr, Hdr->HR.ReqLine, Buf);

       FreeStrBuf(&Buf);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 375 of file context_loop.c.

{
       const char *pch, *pchs, *pche;
       OneHttpHeader *pHdr;
       StrBuf *Line, *LastLine, *HeaderName;
       int nLine = 0;
       void *vF;
       int isbogus = 0;

       HeaderName = NewStrBuf();
       LastLine = NULL;
       do {
              nLine ++;
              Line = NewStrBufPlain(NULL, SIZ / 4);

              if (ClientGetLine(Hdr, Line) < 0) return 1;

              if (StrLength(Line) == 0) {
                     FreeStrBuf(&Line);
                     continue;
              }
              if (nLine == 1) {
                     Hdr->HTTPHeaders = NewHash(1, NULL);
                     pHdr = (OneHttpHeader*) malloc(sizeof(OneHttpHeader));
                     memset(pHdr, 0, sizeof(OneHttpHeader));
                     pHdr->Val = Line;
                     Put(Hdr->HTTPHeaders, HKEY("GET /"), pHdr, DestroyHttpHeaderHandler);
                     syslog(9, "%s", ChrPtr(Line));
                     isbogus = ReadHttpSubject(Hdr, Line, HeaderName);
                     if (isbogus) break;
                     continue;
              }

              /* 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;
              }

              StrBufSanitizeAscii(Line, '');
              StrBufExtract_token(HeaderName, Line, 0, ':');

              pchs = ChrPtr(Line);
              pche = pchs + StrLength(Line);
              pch = pchs + StrLength(HeaderName) + 1;
              pche = pchs + StrLength(Line);
              while ((pch < pche) && isspace(*pch))
                     pch ++;
              StrBufCutLeft(Line, pch - pchs);

              StrBufUpCase(HeaderName);

              pHdr = (OneHttpHeader*) malloc(sizeof(OneHttpHeader));
              memset(pHdr, 0, sizeof(OneHttpHeader));
              pHdr->Val = Line;

              if (GetHash(HttpHeaderHandler, SKEY(HeaderName), &vF) &&
                  (vF != NULL))
              {
                     OneHttpHeader *FHdr = (OneHttpHeader*) vF;
                     pHdr->H = FHdr->H;
                     pHdr->HaveEvaluator = 1;
              }
              Put(Hdr->HTTPHeaders, SKEY(HeaderName), pHdr, DestroyHttpHeaderHandler);
              LastLine = Line;
       } while (Line != NULL);

       FreeStrBuf(&HeaderName);

       return isbogus;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int ReadHttpSubject ( ParsedHttpHdrs Hdr,
StrBuf *  Line,
StrBuf *  Buf 
)

Definition at line 258 of file context_loop.c.

{
       const char *Args;
       void *vLine, *vHandler;
       const char *Pos = NULL;

       Hdr->HR.ReqLine = Line;
       /* The requesttype... GET, POST... */
       StrBufExtract_token(Buf, Hdr->HR.ReqLine, 0, ' ');
       if (GetHash(HttpReqTypes, SKEY(Buf), &vLine) &&
           (vLine != NULL))
       {
              Hdr->HR.eReqType = *(long*)vLine;
       }
       else {
              Hdr->HR.eReqType = eGET;
              return 1;
       }
       StrBufCutLeft(Hdr->HR.ReqLine, StrLength(Buf) + 1);

       /* the HTTP Version... */
       StrBufExtract_token(Buf, Hdr->HR.ReqLine, 1, ' ');
       StrBufCutRight(Hdr->HR.ReqLine, StrLength(Buf) + 1);
       
       if (StrLength(Buf) == 0) {
              Hdr->HR.eReqType = eGET;
              return 1;
       }

       StrBufAppendBuf(Hdr->this_page, Hdr->HR.ReqLine, 0);

       /* chop Filename / query arguments */
       Args = strchr(ChrPtr(Hdr->HR.ReqLine), '?');
       if (Args == NULL) /* whe're not that picky about params... TODO: this will spoil '&' in filenames.*/
              Args = strchr(ChrPtr(Hdr->HR.ReqLine), '&');
       if (Args != NULL) {
              Args ++; /* skip the ? */
              StrBufPlain(Hdr->PlainArgs, 
                         Args, 
                         StrLength(Hdr->HR.ReqLine) -
                         (Args - ChrPtr(Hdr->HR.ReqLine)));
              StrBufCutAt(Hdr->HR.ReqLine, 0, Args - 1);
       } /* don't parse them yet, maybe we don't even care... */
       
       /* now lookup what we are going to do with this... */
       /* skip first slash */
       StrBufExtract_NextToken(Buf, Hdr->HR.ReqLine, &Pos, '/');
       do {
              StrBufExtract_NextToken(Buf, Hdr->HR.ReqLine, &Pos, '/');

              GetHash(HandlerHash, SKEY(Buf), &vHandler),
              Hdr->HR.Handler = (WebcitHandler*) vHandler;
              if (Hdr->HR.Handler == NULL)
                     break;
              /*
               * 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.
               */
              if ((Hdr->HR.Handler->Flags & URLNAMESPACE) != 0)
                     continue;
              break;
       } while (1);
       /* remove the handlername from the URL */
       if ((Pos != NULL) && (Pos != StrBufNOTNULL)){
              StrBufCutLeft(Hdr->HR.ReqLine, 
                           Pos - ChrPtr(Hdr->HR.ReqLine));
       }

       if (Hdr->HR.Handler != NULL) {
              if ((Hdr->HR.Handler->Flags & BOGUS) != 0) {
                     return 1;
              }
              Hdr->HR.DontNeedAuth = (
                     ((Hdr->HR.Handler->Flags & ISSTATIC) != 0) ||
                     ((Hdr->HR.Handler->Flags & ANONYMOUS) != 0)
              );
       }
       else {
              /* If this is a "flat" request for the root, display the configured landing page. */
              int return_value;
              StrBuf *NewLine = NewStrBuf();
              Hdr->HR.DontNeedAuth = 1;
              StrBufAppendPrintf(NewLine, "GET /landing?go=%s HTTP/1.0", ChrPtr(Buf));
              syslog(LOG_DEBUG, "Replacing with: %s", ChrPtr(NewLine));
              return_value = ReadHttpSubject(Hdr, NewLine, Buf);
              FreeStrBuf(&NewLine);
              return return_value;
       }

       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void RegisterHeaderHandler ( const char *  Name,
long  Len,
Header_Evaluator  F 
)

Definition at line 779 of file context_loop.c.

{
       OneHttpHeader *pHdr;
       pHdr = (OneHttpHeader*) malloc(sizeof(OneHttpHeader));
       memset(pHdr, 0, sizeof(OneHttpHeader));
       pHdr->H = F;
       Put(HttpHeaderHandler, Name, Len, pHdr, DestroyHttpHeaderHandler);
}

Here is the caller graph for this function:

Definition at line 773 of file context_loop.c.

{
       DeleteHash(&HttpReqTypes);
       DeleteHash(&HttpHeaderHandler);
}

Here is the caller graph for this function:

void ServerStartModule_CONTEXT ( void  )

Definition at line 724 of file context_loop.c.

{
       long *v;
       HttpReqTypes = NewHash(1, NULL);
       HttpHeaderHandler = NewHash(1, NULL);

       v = malloc(sizeof(long));
       *v = eGET;
       Put(HttpReqTypes, HKEY("GET"), v, NULL);

       v = malloc(sizeof(long));
       *v = ePOST;
       Put(HttpReqTypes, HKEY("POST"), v, NULL);

       v = malloc(sizeof(long));
       *v = eOPTIONS;
       Put(HttpReqTypes, HKEY("OPTIONS"), v, NULL);

       v = malloc(sizeof(long));
       *v = ePROPFIND;
       Put(HttpReqTypes, HKEY("PROPFIND"), v, NULL);

       v = malloc(sizeof(long));
       *v = ePUT;
       Put(HttpReqTypes, HKEY("PUT"), v, NULL);

       v = malloc(sizeof(long));
       *v = eDELETE;
       Put(HttpReqTypes, HKEY("DELETE"), v, NULL);

       v = malloc(sizeof(long));
       *v = eHEAD;
       Put(HttpReqTypes, HKEY("HEAD"), v, NULL);

       v = malloc(sizeof(long));
       *v = eMOVE;
       Put(HttpReqTypes, HKEY("MOVE"), v, NULL);

       v = malloc(sizeof(long));
       *v = eCOPY;
       Put(HttpReqTypes, HKEY("COPY"), v, NULL);

       v = malloc(sizeof(long));
       *v = eREPORT;
       Put(HttpReqTypes, HKEY("REPORT"), v, NULL);
}

Here is the caller graph for this function:

void session_loop ( void  )

Definition at line 589 of file webcit.c.

{
       int xhttp;
       StrBuf *Buf;
       
       /*
        * We stuff these with the values coming from the client cookies,
        * so we can use them to reconnect a timed out session if we have to.
        */
       wcsession *WCC;
      
       WCC= WC;
       WCC->upload_length = 0;
       WCC->upload = NULL;
       WCC->Hdr->nWildfireHeaders = 0;

       if (WCC->Hdr->HR.ContentLength > 0) {
              if (ReadPostData() < 0) {
                     return;
              }
       }

       Buf = NewStrBuf();
       WCC->trailing_javascript = NewStrBuf();

       /* Convert base64-encoded URL's back to plain text */
       if (!strncmp(ChrPtr(WCC->Hdr->this_page), "/B64", 4)) {
              StrBufCutLeft(WCC->Hdr->this_page, 4);
              StrBufDecodeBase64(WCC->Hdr->this_page);
              http_redirect(ChrPtr(WCC->Hdr->this_page));
              goto SKIP_ALL_THIS_CRAP;
       }

       /* If there are variables in the URL, we must grab them now */
       if (WCC->Hdr->PlainArgs != NULL)
              ParseURLParams(WCC->Hdr->PlainArgs);

       /* If the client sent a nonce that is incorrect, kill the request. */
       if (havebstr("nonce")) {
              syslog(9, "Comparing supplied nonce %s to session nonce %d", 
                     bstr("nonce"), WCC->nonce
              );
              if (ibstr("nonce") != WCC->nonce) {
                     syslog(9, "Ignoring request with mismatched nonce.");
                     hprintf("HTTP/1.1 404 Security check failed\r\n");
                     hprintf("Content-Type: text/plain\r\n");
                     begin_burst();
                     wc_printf("Security check failed.\r\n");
                     end_burst();
                     goto SKIP_ALL_THIS_CRAP;
              }
       }

       /*
        * If we're not connected to a Citadel server, try to hook up the connection now.
        */
       if (!WCC->connected) {
              if (GetConnected()) {
                     hprintf("HTTP/1.1 503 Service Unavailable\r\n");
                     hprintf("Content-Type: text/html\r\n");
                     begin_burst();
                     wc_printf("<html><head><title>503 Service Unavailable</title></head><body>\n");
                     wc_printf(_("This program was unable to connect or stay "
                            "connected to the Citadel server.  Please report "
                            "this problem to your system administrator.")
                     );
                     wc_printf("<br>");
                     wc_printf("<a href=\"http://www.citadel.org/doku.php/"
                            "faq:generalquestions:webcit_unable_to_connect\">%s</a>",
                            _("Read More...")
                     );
                     wc_printf("</body></html>\n");
                     end_burst();
                     goto SKIP_ALL_THIS_CRAP;
              }
       }

       /*
        * If we're not logged in, but we have authentication data (either from
        * a cookie or from http-auth), try logging in to Citadel using that.
        */
       if (   (!WCC->logged_in)
              && (StrLength(WCC->Hdr->c_username) > 0)
              && (StrLength(WCC->Hdr->c_password) > 0)
       ) {
              long Status;

              FlushStrBuf(Buf);
              serv_printf("USER %s", ChrPtr(WCC->Hdr->c_username));
              StrBuf_ServGetln(Buf);
              if (GetServerStatus(Buf, &Status) == 3) {
                     serv_printf("PASS %s", ChrPtr(WCC->Hdr->c_password));
                     StrBuf_ServGetln(Buf);
                     if (GetServerStatus(Buf, NULL) == 2) {
                            become_logged_in(WCC->Hdr->c_username,
                                           WCC->Hdr->c_password, Buf);
                     } else {
                            /* Should only display when password is wrong */
                            WCC->ImportantMsg = NewStrBufPlain(ChrPtr(Buf) + 4, StrLength(Buf) - 4);
                            authorization_required();
                            FreeStrBuf(&Buf);
                            goto SKIP_ALL_THIS_CRAP;
                     }
              }
              else if (Status == 541) {
                     WCC->logged_in = 1;
              }
       }

       xhttp = (WCC->Hdr->HR.eReqType != eGET) &&
              (WCC->Hdr->HR.eReqType != ePOST) &&
              (WCC->Hdr->HR.eReqType != eHEAD);

       /*
        * If a 'go' (or 'gotofirst') parameter has been specified, attempt to goto that room
        * prior to doing anything else.
        */
       if (havebstr("go")) {
              int ret;
              syslog(9, "Explicit room selection: %s", bstr("go"));
              ret = gotoroom(sbstr("go"));       /* do quietly to avoid session output! */
              if ((ret/100) != 2) {
                     syslog(1, "Unable to change to [%s]; Reason: %d", bstr("go"), ret);
              }
       }
       else if (havebstr("gotofirst")) {
              int ret;
              syslog(9, "Explicit room selection: %s", bstr("gotofirst"));
              ret = gotoroom(sbstr("gotofirst"));       /* do quietly to avoid session output! */
              if ((ret/100) != 2) {
                     syslog(1, "Unable to change to [%s]; Reason: %d", bstr("gotofirst"), ret);
              }
       }

       /*
        * If we aren't in any room yet, but we have cookie data telling us where we're
        * supposed to be, and 'go' was not specified, then go there.
        */
       else if ( (StrLength(WCC->CurRoom.name) == 0) && ( (StrLength(WCC->Hdr->c_roomname) > 0) )) {
              int ret;

              syslog(9, "We are in '%s' but cookie indicates '%s', going there...",
                     ChrPtr(WCC->CurRoom.name),
                     ChrPtr(WCC->Hdr->c_roomname)
              );
              ret = gotoroom(WCC->Hdr->c_roomname);     /* do quietly to avoid session output! */
              if ((ret/100) != 2) {
                     syslog(1, "COOKIEGOTO: Unable to change to [%s]; Reason: %d",
                            ChrPtr(WCC->Hdr->c_roomname), ret);
              }
       }

       if (WCC->Hdr->HR.Handler != NULL) {
              if (   (!WCC->logged_in)
                     && ((WCC->Hdr->HR.Handler->Flags & ANONYMOUS) == 0)
                     && (WCC->serv_info->serv_supports_guest == 0)
              ) {
                     display_login();
              }
              else {
                     if ((WCC->Hdr->HR.Handler->Flags & AJAX) != 0) {
                            begin_ajax_response();
                     }
                     WCC->Hdr->HR.Handler->F();
                     if ((WCC->Hdr->HR.Handler->Flags & AJAX) != 0) {
                            end_ajax_response();
                     }
              }
       }
       /* When all else fails, display the default landing page or a main menu. */
       else {
              /* 
               * ordinary browser users get a nice login screen, DAV etc. requsets
               * are given a 401 so they can handle it appropriate.
               */
              if (!WCC->logged_in)  {
                     if (xhttp) {
                            authorization_required();
                     }
                     else {
                            display_default_landing_page();
                     }
              }
              /*
               * Toplevel dav requests? or just a flat browser request? 
               */
              else {
                     if (xhttp) {
                            dav_main();
                     }
                     else {
                            display_main_menu();
                     }
              }
       }

SKIP_ALL_THIS_CRAP:
       FreeStrBuf(&Buf);
       fflush(stdout);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void shutdown_sessions ( void  )

Definition at line 48 of file context_loop.c.

{
       wcsession *sptr;
       
       for (sptr = SessionList; sptr != NULL; sptr = sptr->next) {
              sptr->killthis = 1;
       }
}

Here is the caller graph for this function:

void spawn_another_worker_thread ( void  )

Definition at line 419 of file sysdep.c.

{
       pthread_t SessThread;       /* Thread descriptor */
       pthread_attr_t attr; /* Thread attributes */
       int ret;

       ++num_threads_existing;
       ++num_threads_executing;

       /* set attributes for the new thread */
       pthread_attr_init(&attr);
       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

       /*
        * Our per-thread stacks need to be bigger than the default size,
        * otherwise the MIME parser crashes on FreeBSD.
        */
       if ((ret = pthread_attr_setstacksize(&attr, 1024 * 1024))) {
              syslog(1, "pthread_attr_setstacksize: %s\n", strerror(ret));
              pthread_attr_destroy(&attr);
       }

       /* now create the thread */
       if (pthread_create(&SessThread, &attr, (void *(*)(void *)) worker_entry, NULL) != 0) {
              syslog(1, "Can't create thread: %s\n", strerror(errno));
       }

       /* free up the attributes */
       pthread_attr_destroy(&attr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void tmplput_current_user ( StrBuf *  Target,
WCTemplputParams TP 
)

Definition at line 645 of file context_loop.c.

{
       StrBufAppendTemplate(Target, TP, WC->wc_fullname, 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void tmplput_nonce ( StrBuf *  Target,
WCTemplputParams TP 
)

Definition at line 638 of file context_loop.c.

{
       wcsession *WCC = WC;
       StrBufAppendPrintf(Target, "%ld",
                        (WCC != NULL)? WCC->nonce:0);             
}

Here is the caller graph for this function:


Variable Documentation

HashList* HandlerHash

Definition at line 20 of file webcit.c.

HashList* HttpHeaderHandler = NULL

Definition at line 29 of file context_loop.c.

HashList* HttpReqTypes = NULL

Definition at line 28 of file context_loop.c.

pthread_key_t MyConKey

Definition at line 27 of file context_loop.c.

Definition at line 34 of file context_loop.c.

Definition at line 33 of file context_loop.c.

const char* ReqStrs[eNONE]
Initial value:
 {
       "GET",
       "POST",
       "OPTIONS",
       "PROPFIND",
       "PUT",
       "DELETE",
       "HEAD",
       "MOVE",
       "COPY",
       "REPORT"
}

Definition at line 709 of file context_loop.c.

Definition at line 25 of file context_loop.c.

pthread_mutex_t SessionListMutex

Definition at line 23 of file context_loop.c.