diff src/c/urweb.c @ 1877:22b44fe822bf

Take proper account of signatures changing during page generation
author Adam Chlipala <adam@chlipala.net>
date Thu, 10 Oct 2013 14:48:43 -0400
parents 216a3a67ebe3
children 0354df1b6849
line wrap: on
line diff
--- a/src/c/urweb.c	Mon Oct 07 14:08:53 2013 +0400
+++ b/src/c/urweb.c	Thu Oct 10 14:48:43 2013 -0400
@@ -471,6 +471,8 @@
   int amInitializing;
 
   char error_message[ERROR_BUF_LEN];
+
+  int usedSig, needsResig;
 };
 
 size_t uw_headers_max = SIZE_MAX;
@@ -546,6 +548,9 @@
 
   ctx->amInitializing = 0;
 
+  ctx->usedSig = 0;
+  ctx->needsResig = 0;
+
   return ctx;
 }
 
@@ -624,6 +629,8 @@
   ctx->queryString = NULL;
   ctx->nextId = 0;
   ctx->amInitializing = 0;
+  ctx->usedSig = 0;
+  ctx->needsResig = 0;
 }
 
 void uw_reset_keep_request(uw_context ctx) {
@@ -3083,6 +3090,11 @@
   return NULL;
 }
 
+static void set_cookie(uw_context ctx) {
+  if (ctx->usedSig)
+    ctx->needsResig = 1;
+}
+
 uw_unit uw_Basis_set_cookie(uw_context ctx, uw_Basis_string prefix, uw_Basis_string c, uw_Basis_string v, uw_Basis_time *expires, uw_Basis_bool secure) {
   uw_write_header(ctx, "Set-Cookie: ");
   uw_write_header(ctx, c);
@@ -3105,6 +3117,7 @@
   if (secure)
     uw_write_header(ctx, "; secure");
   uw_write_header(ctx, "\r\n");
+  set_cookie(ctx);
 
   return uw_unit_v;
 }
@@ -3115,6 +3128,7 @@
   uw_write_header(ctx, "=; path=");
   uw_write_header(ctx, prefix);
   uw_write_header(ctx, "; " THE_PAST "\r\n");
+  set_cookie(ctx);
 
   return uw_unit_v;
 }
@@ -3192,8 +3206,32 @@
 
 static const char begin_xhtml[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">";
 
+extern int uw_hash_blocksize;
+
+static const char sig_intro[] = "<input type=\"hidden\" name=\"Sig\" value=\"";
+
+static char *find_sig(char *haystack) {
+  int i;
+  char *s = strstr(haystack, sig_intro);
+
+  if (!s || strlen(haystack) - (s - haystack) - (sizeof sig_intro - 1) < uw_hash_blocksize*2+1)
+    return NULL;
+  
+  s += sizeof sig_intro - 1;
+
+  for (i = 0; i < uw_hash_blocksize*2; ++i)
+    if (!isxdigit((int)s[i]))
+      return NULL;
+
+  if (s[i] != '"')
+    return NULL;
+
+  return s;
+}
+
 void uw_commit(uw_context ctx) {
   int i;
+  char *sig;
 
   if (uw_has_error(ctx)) {
     uw_rollback(ctx, 0);
@@ -3316,6 +3354,18 @@
       }
     }
   }
+
+  if (ctx->needsResig) {
+    sig = find_sig(ctx->page.start);
+    if (sig) {
+      char *realsig = ctx->app->cookie_sig(ctx);
+
+      do {
+        memcpy(sig, realsig, 2*uw_hash_blocksize);
+        sig = find_sig(sig);
+      } while (sig);
+    }
+  }
 }
 
 
@@ -3561,8 +3611,6 @@
   return s ? s : "";
 }
 
-extern int uw_hash_blocksize;
-
 uw_Basis_string uw_Basis_makeSigString(uw_context ctx, uw_Basis_string sig) {
   uw_Basis_string r = uw_malloc(ctx, 2 * uw_hash_blocksize + 1);
   int i;
@@ -3591,6 +3639,7 @@
 }
 
 uw_Basis_string uw_Basis_sigString(uw_context ctx, uw_unit u) {
+  ctx->usedSig = 1;
   return ctx->app->cookie_sig(ctx);
 }