]> code.citadel.org Git - citadel.git/blobdiff - webcit/webserver.c
* temporary solution to our ser_readln migration: have a buffer on the session, read...
[citadel.git] / webcit / webserver.c
index 12497ce960003f0bc0984a380844bbf8b83198e7..74bff8c4812c2627fd3c88e7d5103c813ffa6d7d 100644 (file)
@@ -5,7 +5,7 @@
  * waiting on the specified port for incoming HTTP connections.  When a
  * connection is established, it calls context_loop() from context_loop.c.
  *
- * Copyright (c) 1996-2008 by the citadel.org developers.
+ * Copyright (c) 1996-2009 by the citadel.org developers.
  * This program is released under the terms of the GNU General Public License v3.
  *
  */
@@ -27,6 +27,7 @@ int is_https = 0;             /* Nonzero if I am an HTTPS service */
 int follow_xff = 0;            /* Follow X-Forwarded-For: header */
 int home_specified = 0;                /* did the user specify a homedir? */
 int time_to_die = 0;            /* Nonzero if server is shutting down */
+int DisableGzip = 0;
 extern void *context_loop(int*);
 extern void *housekeeping_loop(void);
 extern pthread_mutex_t SessionListMutex;
@@ -198,18 +199,23 @@ int ig_uds_server(char *sockpath, int queue_len)
  *      0       Request timed out.
  *     -1      Connection is broken, or other error.
  */
-int client_read_to(int *sock, StrBuf *Target, StrBuf *Buf, int bytes, int timeout)
+int client_read_to(int *sock, StrBuf *Target, StrBuf *Buf, const char **Pos, int bytes, int timeout)
 {
        const char *Error;
        int retval = 0;
 
 #ifdef HAVE_OPENSSL
        if (is_https) {
+               long bufremain = StrLength(Buf) - (*Pos - ChrPtr(Buf));
+               StrBufAppendBufPlain(Target, *Pos, bufremain, 0);
+               *Pos = NULL;
+               FlushStrBuf(Buf);
+
                while ((StrLength(Buf) + StrLength(Target) < bytes) &&
                       (retval >= 0))
                        retval = client_read_sslbuffer(Buf, timeout);
                if (retval >= 0) {
-                       StrBufAppendBuf(Target, Buf, 0); /// todo: Buf > bytes?
+                       StrBufAppendBuf(Target, Buf, 0); /* todo: Buf > bytes? */
 #ifdef HTTP_TRACING
                        write(2, "\033[32m", 5);
                        write(2, buf, bytes);
@@ -224,14 +230,13 @@ int client_read_to(int *sock, StrBuf *Target, StrBuf *Buf, int bytes, int timeou
        }
 #endif
 
-       if (StrLength(Buf) > 0) {//// todo: what if Buf > bytes?
-               StrBufAppendBuf(Target, Buf, 0);
-       }
-       retval = StrBufReadBLOB(Target, 
-                          sock, 
-                          (StrLength(Target) > 0), 
-                          bytes - StrLength(Target), 
-                               &Error);
+       retval = StrBufReadBLOBBuffered(Target, 
+                                       Buf, Pos, 
+                                       sock, 
+                                       1, 
+                                       bytes,
+                                       O_TERM,
+                                       &Error);
        if (retval < 0) {
                lprintf(2, "client_read() failed: %s\n",
                        Error);
@@ -252,8 +257,9 @@ int client_read_to(int *sock, StrBuf *Target, StrBuf *Buf, int bytes, int timeou
  */
 void begin_burst(void)
 {
-       if (WC->WBuf == NULL)
+       if (WC->WBuf == NULL) {
                WC->WBuf = NewStrBufPlain(NULL, 32768);
+       }
 }
 
 
@@ -262,20 +268,17 @@ void begin_burst(void)
  */
 long end_burst(void)
 {
-       struct wcsession *WCC = WC;
+       wcsession *WCC = WC;
         const char *ptr, *eptr;
         long count;
        ssize_t res;
         fd_set wset;
         int fdflags;
 
-#ifdef HAVE_ZLIB
-       /* Perform gzip compression, if enabled and supported by client */
-       if ((WCC->gzip_ok) && CompressBuffer(WCC->WBuf))
+       if (!DisableGzip && (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));
 
@@ -357,65 +360,6 @@ long end_burst(void)
 }
 
 
-
-/*
- * 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)
- *
- * sock                the socket fd to read from
- * buf         the buffer to write to
- * bytes       Number of bytes to read
- */
-int client_read(int *sock, StrBuf *Target, StrBuf *buf, int bytes)
-{
-       return (client_read_to(sock, Target, buf, bytes, SLEEPING));
-}
-
-
-/*
- * 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)
- *
- * sock                socket fd to get client line from
- * buf         buffer to write read data to
- * bufsiz      how many bytes to read
- *
- * returns the number of bytes read
- */
-/////int client_getln(int *sock, char *buf, int bufsiz)
-/////{
-/////  int i, retval;
-/////
-/////  /* Read one character at a time.*/
-/////  for (i = 0; *sock > 0; i++) {
-/////          retval = client_read(sock, &buf[i], 1);
-/////          if (retval < 0)
-/////                  return retval;
-/////          if (retval != 1 || buf[i] == '\n' || i == (bufsiz-1))
-/////                  break;
-/////          if ( (!isspace(buf[i])) && (!isprint(buf[i])) ) {
-/////                  /* Non printable character recieved from client */
-/////                  return(-1);
-/////          }
-/////  }
-/////
-/////  /* If we got a long line, discard characters until the newline. */
-/////  if (i == (bufsiz-1))
-/////          while (buf[i] != '\n' && retval == 1)
-/////                  retval = client_read(sock, &buf[i], 1);
-/////
-/////  /*
-/////   * Strip any trailing non-printable characters.
-/////   */
-/////  buf[i] = 0;
-/////  while ((i > 0) && (!isprint(buf[i - 1]))) {
-/////          buf[--i] = 0;
-/////  }
-/////  return (retval);
-/////}
-
 /*
  * Shut us down the regular way.
  * signum is the signal we want to forward
@@ -429,11 +373,12 @@ void graceful_shutdown_watcher(int signum) {
 }
 
 
-int ClientGetLine(int *sock, StrBuf *Target, StrBuf *CLineBuf)
+int ClientGetLine(int *sock, StrBuf *Target, StrBuf *CLineBuf, const char **Pos)
 {
        const char *Error, *pch, *pchs;
        int rlen, len, retval = 0;
 
+#ifdef HAVE_OPENSSL
        if (is_https) {
                int ntries = 0;
                if (StrLength(CLineBuf) > 0) {
@@ -481,12 +426,14 @@ int ClientGetLine(int *sock, StrBuf *Target, StrBuf *CLineBuf)
                        return -1;
        }
        else 
-               return StrBufTCP_read_buffered_line(Target, 
-                                                   CLineBuf,
-                                                   sock,
-                                                   5,
-                                                   1,
-                                                   &Error);
+#endif
+               return StrBufTCP_read_buffered_line_fast(Target, 
+                                                        CLineBuf,
+                                                        Pos,
+                                                        sock,
+                                                        5,
+                                                        1,
+                                                        &Error);
 }
 
 
@@ -497,7 +444,6 @@ int ClientGetLine(int *sock, StrBuf *Target, StrBuf *CLineBuf)
  */
 pid_t current_child;
 void graceful_shutdown(int signum) {
-//     kill(current_child, signum);
        char wd[SIZ];
        FILE *FD;
        int fd;
@@ -558,16 +504,12 @@ void start_daemon(char *pid_file)
                        exit(errno);
                }
        
-               else if (current_child == 0) {  // child process
-//                     signal(SIGTERM, graceful_shutdown);
+               else if (current_child == 0) {  /* child process */
                        signal(SIGHUP, graceful_shutdown);
 
                        return; /* continue starting webcit. */
                }
-       
-               else { // watcher process
-//                     signal(SIGTERM, SIG_IGN);
-//                     signal(SIGHUP, SIG_IGN);
+               else { /* watcher process */
                        if (pid_file) {
                                fp = fopen(pid_file, "w");
                                if (fp != NULL) {
@@ -650,15 +592,19 @@ void spawn_another_worker_thread()
        pthread_attr_destroy(&attr);
 }
 
-//#define DBG_PRINNT_HOOKS_AT_START
+/* #define DBG_PRINNT_HOOKS_AT_START */
 #ifdef DBG_PRINNT_HOOKS_AT_START
 const char foobuf[32];
 const char *nix(void *vptr) {snprintf(foobuf, 32, "%0x", (long) vptr); return foobuf;}
 #endif 
+extern int dbg_analyze_msg;
+extern int dbg_bactrace_template_errors;
+extern int DumpTemplateI18NStrings;
+extern StrBuf *I18nDump;
 void InitTemplateCache(void);
 extern int LoadTemplates;
 extern void LoadZoneFiles(void);
-
+StrBuf *csslocal = NULL;
 /*
  * Here's where it all begins.
  */
@@ -683,6 +629,9 @@ int main(int argc, char **argv)
        char *mo = NULL;
 #endif /* ENABLE_NLS */
        char uds_listen_path[PATH_MAX]; /* listen on a unix domain socket? */
+       const char *I18nDumpFile = NULL;
+
+       WildFireInitBacktrace(argv[0], 2);
 
        HandlerHash = NewHash(1, NULL);
        PreferenceHooks = NewHash(1, NULL);
@@ -692,9 +641,12 @@ int main(int argc, char **argv)
        TemplateCache = NewHash(1, NULL);
        GlobalNS = NewHash(1, NULL);
        Iterators = NewHash(1, NULL);
-       Contitionals = NewHash(1, NULL);
-       LoadZoneFiles();
+       Conditionals = NewHash(1, NULL);
+       MsgHeaderHandler = NewHash(1, NULL);
+       MimeRenderHandler = NewHash(1, NULL);
+       SortHash = NewHash(1, NULL);
 
+       LoadZoneFiles();
 
 #ifdef DBG_PRINNT_HOOKS_AT_START
        dbg_PrintHash(HandlerHash, nix, NULL);
@@ -713,9 +665,9 @@ int main(int argc, char **argv)
 
        /* Parse command line */
 #ifdef HAVE_OPENSSL
-       while ((a = getopt(argc, argv, "h:i:p:t:T:x:dD:cfs")) != EOF)
+       while ((a = getopt(argc, argv, "h:i:p:t:T:x:dD:G:cfsZ")) != EOF)
 #else
-       while ((a = getopt(argc, argv, "h:i:p:t:T:x:dD:cf")) != EOF)
+       while ((a = getopt(argc, argv, "h:i:p:t:T:x:dD:G:cfZ")) != EOF)
 #endif
                switch (a) {
                case 'h':
@@ -754,6 +706,11 @@ int main(int argc, char **argv)
                        break;
                case 'T':
                        LoadTemplates = atoi(optarg);
+                       dbg_analyze_msg = (LoadTemplates && (1<<1)) != 0;
+                       dbg_bactrace_template_errors = (LoadTemplates && (1<<2)) != 0;
+                       break;
+               case 'Z':
+                       DisableGzip = 1;
                        break;
                case 'x':
                        verbosity = atoi(optarg);
@@ -779,12 +736,17 @@ int main(int argc, char **argv)
                case 's':
                        is_https = 1;
                        break;
+               case 'G':
+                       DumpTemplateI18NStrings = 1;
+                       I18nDump = NewStrBufPlain(HKEY("int templatestrings(void)\n{\n"));
+                       I18nDumpFile = optarg;
+                       break;
                default:
                        fprintf(stderr, "usage: webcit "
                                "[-i ip_addr] [-p http_port] "
                                "[-t tracefile] [-c] [-f] "
                                "[-T Templatedebuglevel] "
-                               "[-d] "
+                               "[-d] [-Z] [-G i18ndumpfile] "
 #ifdef HAVE_OPENSSL
                                "[-s] "
 #endif
@@ -799,17 +761,16 @@ int main(int argc, char **argv)
        }
 
        /* daemonize, if we were asked to */
-       if (running_as_daemon) {
+       if (!DumpTemplateI18NStrings && running_as_daemon) {
                start_daemon(pidfile);
        }
        else {
-///            signal(SIGTERM, graceful_shutdown);
                signal(SIGHUP, graceful_shutdown);
        }
 
        /* Tell 'em who's in da house */
        lprintf(1, PACKAGE_STRING "\n");
-       lprintf(1, "Copyright (C) 1996-2008 by the Citadel development team.\n"
+       lprintf(1, "Copyright (C) 1996-2009 by the Citadel development team.\n"
                "This software is distributed under the terms of the "
                "GNU General Public License.\n\n"
        );
@@ -819,6 +780,7 @@ int main(int argc, char **argv)
 #ifdef ENABLE_NLS
        initialize_locales();
 
+
        locale = setlocale(LC_ALL, "");
 
        mo = malloc(strlen(webcitdir) + 20);
@@ -826,7 +788,6 @@ int main(int argc, char **argv)
        free(mo);
        lprintf(9, "Text domain: %s\n", textdomain("webcit"));
        lprintf(9, "Text domain Charset: %s\n", bind_textdomain_codeset("webcit","UTF8"));
-       preset_locale();
 #endif
 
 
@@ -870,15 +831,43 @@ int main(int argc, char **argv)
                perror("chdir");
        }
        LoadIconDir(static_icon_dir);
-       InitTemplateCache();
 
        initialise_modules();
        initialize_viewdefs();
        initialize_axdefs();
 
+       InitTemplateCache();
+       if (DumpTemplateI18NStrings) {
+               FILE *fd;
+               StrBufAppendBufPlain(I18nDump, HKEY("}\n"), 0);
+               if (StrLength(I18nDump) < 50) {
+                       lprintf(1, "********************************************************************************\n");
+                       lprintf(1, "*        No strings found in templates! are you shure they're there?           *\n");
+                       lprintf(1, "********************************************************************************\n");
+                       return -1;
+               }
+               fd = fopen(I18nDumpFile, "w");
+               if (fd == NULL) {
+                       lprintf(1, "********************************************************************************\n");
+                       lprintf(1, "*                  unable to open I18N dumpfile [%s]         *\n", I18nDumpFile);
+                       lprintf(1, "********************************************************************************\n");
+                       return -1;
+               }
+               fwrite(ChrPtr(I18nDump), 1, StrLength(I18nDump), fd);
+               fclose(fd);
+               return 0;
+       }
+
+       if (!access("static.local/webcit.css", R_OK)) {
+               csslocal = NewStrBufPlain(HKEY("<link href=\"static.local/webcit.css\" rel=\"stylesheet\" type=\"text/css\">"));
+       }
+
        /* Tell libical to return an error instead of aborting if it sees badly formed iCalendar data. */
        icalerror_errors_are_fatal = 0;
 
+       /* Use our own prefix on tzid's generated from system tzdata */
+       icaltimezone_set_tzid_prefix("/citadel.org/");
+
        /*
         * Set up a place to put thread-specific data.
         * We only need a single pointer per thread - it points to the
@@ -968,7 +957,10 @@ void ShutDownWebcit(void)
        DeleteHash(&TemplateCache);
        DeleteHash(&LocalTemplateCache);
        DeleteHash(&Iterators);
-       DeleteHash(&Contitionals);
+       DeleteHash(&MimeRenderHandler);
+       DeleteHash(&Conditionals);
+       DeleteHash(&MsgHeaderHandler);
+       DeleteHash(&SortHash);
 #ifdef ENABLE_NLS
        ShutdownLocale();
 #endif
@@ -1012,19 +1004,19 @@ void worker_entry(void)
                        if (msock > 0)  ret = select(msock+1, &tempset, NULL, NULL,  &tv);
                        end_critical_section(S_SELECT);
                        if ((ret < 0) && (errno != EINTR) && (errno != EAGAIN))
-                       {// EINTR and EAGAIN are thrown but not of interest.
+                       {/* EINTR and EAGAIN are thrown but not of interest. */
                                lprintf(2, "accept() failed:%d %s\n",
                                        errno, strerror(errno));
                        }
                        else if ((ret > 0) && (msock > 0) && FD_ISSET(msock, &tempset))
-                       {// Successfully selected, and still not shutting down? Accept!
+                       {/* Successfully selected, and still not shutting down? Accept! */
                                ssock = accept(msock, NULL, 0);
                        }
                        
                } while ((msock > 0) && (ssock < 0)  && (time_to_die == 0));
 
                if ((msock == -1)||(time_to_die))
-               {// ok, we're going down.
+               {/* ok, we're going down. */
                        int shutdown = 0;
 
                        /* the first to come here will have to do the cleanup.
@@ -1038,11 +1030,11 @@ void worker_entry(void)
                        }
                        end_critical_section(S_SHUTDOWN);
                        if (shutdown == 1)
-                       {// we're the one to cleanup the mess.
+                       {/* we're the one to cleanup the mess. */
                                lprintf(2, "I'm master shutdown: tagging sessions to be killed.\n");
                                shutdown_sessions();
                                lprintf(2, "master shutdown: waiting for others\n");
-                               sleeeeeeeeeep(1); // wait so some others might finish...
+                               sleeeeeeeeeep(1); /* wait so some others might finish... */
                                lprintf(2, "master shutdown: cleaning up sessions\n");
                                do_housekeeping();
                                lprintf(2, "master shutdown: cleaning up libical\n");
@@ -1060,7 +1052,7 @@ void worker_entry(void)
                        if (ssock > 0) close (ssock);
                        lprintf(2, "inbetween.");
                        pthread_exit(NULL);
-               } else { // Got it? do some real work!
+               } else { /* Got it? do some real work! */
                        /* Set the SO_REUSEADDR socket option */
                        i = 1;
                        setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR,