+ log_error(LOG_LEVEL_ERROR,
+ "At least one of the variables in \'%s\' had to "
+ "be truncated before compilation", pattern->str);
+ }
+ if (job_list == NULL)
+ {
+ job_list = dummy;
+ }
+ else
+ {
+ lastjob->next = dummy;
+ }
+ lastjob = dummy;
+ }
+ }
+
+ return job_list;
+}
+
+
+/*********************************************************************
+ *
+ * Function : rewrite_url
+ *
+ * Description : Rewrites a URL with a single pcrs command
+ * and returns the result if it differs from the
+ * original and isn't obviously invalid.
+ *
+ * Parameters :
+ * 1 : old_url = URL to rewrite.
+ * 2 : pcrs_command = pcrs command formatted as string (s@foo@bar@)
+ *
+ *
+ * Returns : NULL if the pcrs_command didn't change the url, or
+ * the result of the modification.
+ *
+ *********************************************************************/
+char *rewrite_url(char *old_url, const char *pcrs_command)
+{
+ char *new_url = NULL;
+ int hits;
+
+ assert(old_url);
+ assert(pcrs_command);
+
+ new_url = pcrs_execute_single_command(old_url, pcrs_command, &hits);
+
+ if (hits == 0)
+ {
+ log_error(LOG_LEVEL_REDIRECTS,
+ "pcrs command \"%s\" didn't change \"%s\".",
+ pcrs_command, old_url);
+ freez(new_url);
+ }
+ else if (hits < 0)
+ {
+ log_error(LOG_LEVEL_REDIRECTS,
+ "executing pcrs command \"%s\" to rewrite %s failed: %s",
+ pcrs_command, old_url, pcrs_strerror(hits));
+ freez(new_url);
+ }
+ else if (strncmpic(new_url, "http://", 7) && strncmpic(new_url, "https://", 8))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "pcrs command \"%s\" changed \"%s\" to \"%s\" (%u hi%s), "
+ "but the result doesn't look like a valid URL and will be ignored.",
+ pcrs_command, old_url, new_url, hits, (hits == 1) ? "t" : "ts");
+ freez(new_url);
+ }
+ else
+ {
+ log_error(LOG_LEVEL_REDIRECTS,
+ "pcrs command \"%s\" changed \"%s\" to \"%s\" (%u hi%s).",
+ pcrs_command, old_url, new_url, hits, (hits == 1) ? "t" : "ts");
+ }
+
+ return new_url;
+
+}
+
+
+#ifdef FEATURE_FAST_REDIRECTS
+/*********************************************************************
+ *
+ * Function : get_last_url
+ *
+ * Description : Search for the last URL inside a string.
+ * If the string already is a URL, it will
+ * be the first URL found.
+ *
+ * Parameters :
+ * 1 : subject = the string to check
+ * 2 : redirect_mode = +fast-redirect{} mode
+ *
+ * Returns : NULL if no URL was found, or
+ * the last URL found.
+ *
+ *********************************************************************/
+char *get_last_url(char *subject, const char *redirect_mode)
+{
+ char *new_url = NULL;
+ char *tmp;
+
+ assert(subject);
+ assert(redirect_mode);
+
+ subject = strdup(subject);
+ if (subject == NULL)
+ {
+ log_error(LOG_LEVEL_ERROR, "Out of memory while searching for redirects.");
+ return NULL;
+ }
+
+ if (0 == strcmpic(redirect_mode, "check-decoded-url") && strchr(subject, '%'))
+ {
+ char *url_segment = NULL;
+ char **url_segments;
+ size_t max_segments;
+ int segments;
+
+ log_error(LOG_LEVEL_REDIRECTS,
+ "Checking \"%s\" for encoded redirects.", subject);
+
+ /*
+ * Check each parameter in the URL separately.
+ * Sectionize the URL at "?" and "&",
+ * go backwards through the segments, URL-decode them
+ * and look for a URL in the decoded result.
+ * Stop the search after the first match.
+ *
+ * XXX: This estimate is guaranteed to be high enough as we
+ * let ssplit() ignore empty fields, but also a bit wasteful.
+ */
+ max_segments = strlen(subject) / 2;
+ url_segments = malloc(max_segments * sizeof(char *));
+
+ if (NULL == url_segments)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Out of memory while decoding URL: %s", subject);
+ freez(subject);
+ return NULL;
+ }
+
+ segments = ssplit(subject, "?&", url_segments, max_segments);
+
+ while (segments-- > 0)
+ {
+ char *dtoken = url_decode(url_segments[segments]);
+ if (NULL == dtoken)
+ {
+ log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", url_segments[segments]);
+ continue;
+ }
+ url_segment = strstr(dtoken, "http://");
+ if (NULL == url_segment)
+ {
+ url_segment = strstr(dtoken, "https://");
+ }
+ if (NULL != url_segment)
+ {
+ url_segment = strdup(url_segment);
+ freez(dtoken);
+ if (url_segment == NULL)