/** Explode time to human readable form. */
 log4cxx_status_t explode( apr_time_exp_t * result, log4cxx_time_t input ) const
 {
    apr_status_t stat;
    //  APR 1.1 and early mishandles microseconds on dates
    //   before 1970, APR bug 32520
    if (LOG4CXX_UNLIKELY(input < 0 && apr_time_usec(input) < 0)) {
       apr_time_t floorTime = (apr_time_sec(input) -1) * APR_USEC_PER_SEC;
       stat = apr_time_exp_gmt(result, floorTime);
       result->tm_usec = (int) (input - floorTime);
    } else {
       stat = apr_time_exp_gmt( result, input );
    }
    return stat;
 }
Example #2
0
bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const
{
	apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);
	
	apr_time_exp_t exp_time;
	if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
	{
		return false;
	}

	if (year)
		*year = exp_time.tm_year + 1900;

	if (month)
		*month = exp_time.tm_mon + 1;

	if (day)
		*day = exp_time.tm_mday;

	if (hour)
		*hour = exp_time.tm_hour;

	if (min)
		*min = exp_time.tm_min;

	if (sec)
		*sec = exp_time.tm_sec;

	return true;
}
/* NOTE: buf must be at least DAV_TIMEBUF_SIZE chars in size */
void
dav_format_time(int style, apr_time_t sec, char *buf)
{
	apr_time_exp_t tms;

	/* ### what to do if fails? */
	(void) apr_time_exp_gmt(&tms, sec);

	if (style == DAV_STYLE_ISO8601) {
		/* ### should we use "-00:00" instead of "Z" ?? */

		/* 20 chars plus null term */
		sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ",
				tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
				tms.tm_hour, tms.tm_min, tms.tm_sec);
		return;
	}

	/* RFC 822 date format; as strftime '%a, %d %b %Y %T GMT' */

	/* 29 chars plus null term */
	sprintf(buf,
			"%s, %.2d %s %d %.2d:%.2d:%.2d GMT",
			apr_day_snames[tms.tm_wday],
			tms.tm_mday, apr_month_snames[tms.tm_mon],
			tms.tm_year + 1900,
			tms.tm_hour, tms.tm_min, tms.tm_sec);
}
Example #4
0
const char *
svn_time_to_cstring(apr_time_t when, apr_pool_t *pool)
{
    apr_time_exp_t exploded_time;

    /* We toss apr_status_t return value here -- for one thing, caller
       should pass in good information.  But also, where APR's own code
       calls these functions it tosses the return values, and
       furthermore their current implementations can only return success
       anyway. */

    /* We get the date in GMT now -- and expect the tm_gmtoff and
       tm_isdst to be not set. We also ignore the weekday and yearday,
       since those are not needed. */

    apr_time_exp_gmt(&exploded_time, when);

    /* It would be nice to use apr_strftime(), but APR doesn't give a
       way to convert back, so we wouldn't be able to share the format
       string between the writer and reader. */
    return apr_psprintf(pool,
                        TIMESTAMP_FORMAT,
                        exploded_time.tm_year + 1900,
                        exploded_time.tm_mon + 1,
                        exploded_time.tm_mday,
                        exploded_time.tm_hour,
                        exploded_time.tm_min,
                        exploded_time.tm_sec,
                        exploded_time.tm_usec);
}
Example #5
0
/*
 * Sets into the saved_request the designated filename, according to configured base
 * directory and request data (URI, headers, etc). Also creates the base directory if it
 * doesn't exist
 */
static int set_filename(tee_saved_request *sr)
{
	apr_time_exp_t t;
	apr_time_exp_gmt(&t, sr->time_enqueued);

	// Obtaining directory name
	const char *dir;
	dir = apr_psprintf(sr->pool, "%s/%04d%02d%02d/%02d",
			sr->base_dir, 1900 + t.tm_year, t.tm_mon + 1, t.tm_mday, t.tm_hour);

	// Creating directory if needed
	apr_status_t rc = apr_dir_make_recursive(dir, APR_FPROT_OS_DEFAULT, sr->pool);
	if (rc != APR_SUCCESS) {
		ap_log_error(APLOG_MARK, APLOG_ERR, 0, sr->server, "tee: Cannot create directory %s: %s",
				dir, tee_get_error_string(rc, sr->pool));
		return 1;
	}

	// Setting file name
	unsigned long file_id = ((unsigned long) t.tm_min * 60 + t.tm_sec) * 1000000 + t.tm_usec; // usec in hour
	char b[MAX_FILENAME_LEN]; // Filename is cut in case the URI is too long
	const char *rec_id = get_header_value(sr, sr->id_header, "");
	const char *host = get_header_value(sr, "Host", "");
	apr_snprintf(b, MAX_FILENAME_LEN, "%010lu_%s_%s_%s%s", file_id, rec_id, sr->method, host, sr->uri);
	tee_replace(b, "/", '_'); // Replace the slash (invalid character in file names)
	sr->filename = apr_psprintf(sr->pool, "%s/%s_%d", dir, b, sr->status);
	return 0;
}
Example #6
0
void LLDate::toHTTPDateStream(std::ostream& s) const
{
    // http://apr.apache.org/docs/apr/0.9/group__apr__time.html
    apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);

    apr_time_exp_t exp_time ; //Apache time module

    if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
    {
        // Return Epoch UTC date
        s << "Thursday, 01 Jan 1970 00:00:00 GMT" ;
        return;
    }

    s << std::dec << std::setfill('0');
#if( LL_WINDOWS || __GNUC__ > 2)
    s << std::right ;
#else
    s.setf(ios::right);
#endif    
    std::string day = weekdays[exp_time.tm_wday];
    std::string month = months[exp_time.tm_mon];

    s << std::setw(day.length()) << (day)
      << ", " << std::setw(2) << (exp_time.tm_mday)
      << ' ' << std::setw(month.length()) << (month)
      << ' ' << std::setw(4) << (exp_time.tm_year + 1900)
	  << ' ' << std::setw(2) << (exp_time.tm_hour)
	  << ':' << std::setw(2) << (exp_time.tm_min)
	  << ':' << std::setw(2) << (exp_time.tm_sec)
      << " GMT";

    // RFC 1123 date does not use microseconds
    llinfos << "Date in RFC 1123 format is " << s << llendl;
}
Example #7
0
void LLDate::toStream(std::ostream& s) const
{
	apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);
	
	apr_time_exp_t exp_time;
	if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
	{
		s << "1970-01-01T00:00:00Z";
		return;
	}
	
	s << std::dec << std::setfill('0');
#if( LL_WINDOWS || __GNUC__ > 2)
	s << std::right;
#else
	s.setf(ios::right);
#endif
	s		 << std::setw(4) << (exp_time.tm_year + 1900)
	  << '-' << std::setw(2) << (exp_time.tm_mon + 1)
	  << '-' << std::setw(2) << (exp_time.tm_mday)
	  << 'T' << std::setw(2) << (exp_time.tm_hour)
	  << ':' << std::setw(2) << (exp_time.tm_min)
	  << ':' << std::setw(2) << (exp_time.tm_sec);
	if (exp_time.tm_usec > 0)
	{
		s << '.' << std::setw(2)
		  << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100));
	}
	s << 'Z';
}
Example #8
0
static void jk2_logger_file_setTimeStr(jk_env_t *env, char *str, int len)
{
    apr_time_exp_t gmt;
    apr_size_t     l;

    apr_time_exp_gmt(&gmt, apr_time_now());
    apr_strftime(str, &l, len, jk2_logger_file_logFmt, &gmt);
}
Example #9
0
static void make_cookie(request_rec *r)
{
    cookie_log_state *cls = ap_get_module_config(r->server->module_config,
                                                 &usertrack_module);
    char cookiebuf[2 * (sizeof(apr_uint64_t) + sizeof(int)) + 2];
    unsigned int random;
    apr_time_t now = r->request_time ? r->request_time : apr_time_now();
    char *new_cookie;
    cookie_dir_rec *dcfg;

    ap_random_insecure_bytes(&random, sizeof(random));
    apr_snprintf(cookiebuf, sizeof(cookiebuf), "%x.%" APR_UINT64_T_HEX_FMT,
                 random, (apr_uint64_t)now);
    dcfg = ap_get_module_config(r->per_dir_config, &usertrack_module);
    if (cls->expires) {

        /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */
        new_cookie = apr_psprintf(r->pool, "%s=%s; path=/",
                                  dcfg->cookie_name, cookiebuf);

        if ((dcfg->style == CT_UNSET) || (dcfg->style == CT_NETSCAPE)) {
            apr_time_exp_t tms;
            apr_time_exp_gmt(&tms, r->request_time
                                 + apr_time_from_sec(cls->expires));
            new_cookie = apr_psprintf(r->pool,
                                       "%s; expires=%s, "
                                       "%.2d-%s-%.2d %.2d:%.2d:%.2d GMT",
                                       new_cookie, apr_day_snames[tms.tm_wday],
                                       tms.tm_mday,
                                       apr_month_snames[tms.tm_mon],
                                       tms.tm_year % 100,
                                       tms.tm_hour, tms.tm_min, tms.tm_sec);
        }
        else {
            new_cookie = apr_psprintf(r->pool, "%s; max-age=%d",
                                      new_cookie, cls->expires);
        }
    }
    else {
        new_cookie = apr_psprintf(r->pool, "%s=%s; path=/",
                                  dcfg->cookie_name, cookiebuf);
    }
    if (dcfg->cookie_domain != NULL) {
        new_cookie = apr_pstrcat(r->pool, new_cookie, "; domain=",
                                 dcfg->cookie_domain,
                                 (dcfg->style == CT_COOKIE2
                                  ? "; version=1"
                                  : ""),
                                 NULL);
    }

    apr_table_addn(r->err_headers_out,
                   (dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"),
                   new_cookie);
    apr_table_setn(r->notes, "cookie", apr_pstrdup(r->pool, cookiebuf));   /* log first time */
    return;
}
Example #10
0
static void test_gmtstr(CuTest *tc)
{
    apr_status_t rv;
    apr_time_exp_t xt;

    rv = apr_time_exp_gmt(&xt, now);
    if (rv == APR_ENOTIMPL) {
        CuNotImpl(tc, "apr_time_exp_gmt");
    }
    CuAssertTrue(tc, rv == APR_SUCCESS);
    CuAssertStrEquals(tc, "2002-08-14 19:05:36.186711 +0000 [257 Sat]", 
                      print_time(p, &xt));
}
Example #11
0
static void test_imp_gmt(CuTest *tc)
{
    apr_status_t rv;
    apr_time_exp_t xt;
    apr_time_t imp;

    rv = apr_time_exp_gmt(&xt, now);
    CuAssertTrue(tc, rv == APR_SUCCESS);
    rv = apr_time_exp_gmt_get(&imp, &xt);
    if (rv == APR_ENOTIMPL) {
        CuNotImpl(tc, "apr_time_exp_gmt_get");
    }
    CuAssertTrue(tc, rv == APR_SUCCESS);
    CuAssertTrue(tc, now == imp);
}
Example #12
0
static void test_strftimesmall(CuTest *tc)
{
    apr_status_t rv;
    apr_time_exp_t xt;
    char str[STR_SIZE];
    apr_size_t sz;

    rv = apr_time_exp_gmt(&xt, now);
    rv = apr_strftime(str, &sz, STR_SIZE, "%T", &xt);
    if (rv == APR_ENOTIMPL) {
        CuNotImpl(tc, "apr_strftime");
    }
    CuAssertTrue(tc, rv == APR_SUCCESS);
    CuAssertStrEquals(tc, "19:05:36", str);
}
Example #13
0
static void test_strftime(CuTest *tc)
{
    apr_status_t rv;
    apr_time_exp_t xt;
    char *str = NULL;
    apr_size_t sz;

    rv = apr_time_exp_gmt(&xt, now);
    str = apr_palloc(p, STR_SIZE + 1);
    rv = apr_strftime(str, &sz, STR_SIZE, "%R %A %d %B %Y", &xt);
    if (rv == APR_ENOTIMPL) {
        CuNotImpl(tc, "apr_strftime");
    }
    CuAssertTrue(tc, rv == APR_SUCCESS);
    CuAssertStrEquals(tc, "19:05 Saturday 14 September 2002", str);
}
Example #14
0
APR_DECLARE(apr_status_t) apr_rfc822_date(char *date_str, apr_time_t t)
{
    apr_time_exp_t xt;
    const char *s;
    int real_year;

    apr_time_exp_gmt(&xt, t);

    /* example: "Sat, 08 Jan 2000 18:31:41 GMT" */
    /*           12345678901234567890123456789  */

    s = &apr_day_snames[xt.tm_wday][0];
    *date_str++ = *s++;
    *date_str++ = *s++;
    *date_str++ = *s++;
    *date_str++ = ',';
    *date_str++ = ' ';
    *date_str++ = xt.tm_mday / 10 + '0';
    *date_str++ = xt.tm_mday % 10 + '0';
    *date_str++ = ' ';
    s = &apr_month_snames[xt.tm_mon][0];
    *date_str++ = *s++;
    *date_str++ = *s++;
    *date_str++ = *s++;
    *date_str++ = ' ';
    real_year = 1900 + xt.tm_year;
    /* This routine isn't y10k ready. */
    *date_str++ = real_year / 1000 + '0';
    *date_str++ = real_year % 1000 / 100 + '0';
    *date_str++ = real_year % 100 / 10 + '0';
    *date_str++ = real_year % 10 + '0';
    *date_str++ = ' ';
    *date_str++ = xt.tm_hour / 10 + '0';
    *date_str++ = xt.tm_hour % 10 + '0';
    *date_str++ = ':';
    *date_str++ = xt.tm_min / 10 + '0';
    *date_str++ = xt.tm_min % 10 + '0';
    *date_str++ = ':';
    *date_str++ = xt.tm_sec / 10 + '0';
    *date_str++ = xt.tm_sec % 10 + '0';
    *date_str++ = ' ';
    *date_str++ = 'G';
    *date_str++ = 'M';
    *date_str++ = 'T';
    *date_str++ = 0;
    return APR_SUCCESS;
}
Example #15
0
static void test_exp_get_gmt(CuTest *tc)
{
    apr_status_t rv;
    apr_time_exp_t xt;
    apr_time_t imp;
    apr_int64_t hr_off_64;

    rv = apr_time_exp_gmt(&xt, now);
    CuAssertTrue(tc, rv == APR_SUCCESS);
    rv = apr_time_exp_get(&imp, &xt);
    if (rv == APR_ENOTIMPL) {
        CuNotImpl(tc, "apr_time_exp_get");
    }
    CuAssertTrue(tc, rv == APR_SUCCESS);
    hr_off_64 = (apr_int64_t) xt.tm_gmtoff * APR_USEC_PER_SEC;
    CuAssertTrue(tc, now + hr_off_64 == imp);
}
Example #16
0
static apr_file_t *ap_open_log(apr_pool_t *p, server_rec *s, const char *base, log_options *ls, apr_time_t tm) {
    if (*base == '|') {
        /* We have piped log handling here because once log rotation has been
         * enabled we become responsible for /all/ transfer log output server
         * wide. That's a consequence of the way the log output hooks in
         * mod_log_config are implemented. Unfortunately this means we have to
         * duplicate functionality from mod_log_config. Note that we don't
         * support the buffered logging mode that mlc implements.
         */
        piped_log *pl;

        if (ls->enabled) {
            /* Can't rotate a piped log */
            ls->enabled = 0;
            ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, s,
                            "disabled log rotation for piped log %s.", base);
        }

        if (pl = ap_open_piped_log(p, base + 1), NULL == pl) {
           return NULL;
        }

        return ap_piped_log_write_fd(pl);
    }
    else
    {
        apr_file_t *fd;
        apr_status_t rv;
        const char *name = ap_server_root_relative(p, base);

        if (NULL == name) {
            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
                            "invalid transfer log path %s.", base);
            return NULL;
        }

        if (ls->enabled) {
            apr_time_t log_time = tm - ls->offset;
            if (strchr(base, '%') != NULL) {
                apr_time_exp_t e;

                apr_time_exp_gmt(&e, log_time);
                name = ap_pstrftime(p, name, &e);
            }
            else
            {
                /* Synthesize the log name using the specified time in seconds as a
                 * suffix.  We subtract the offset here because it was added when
                 * quantizing the time but we want the name to reflect the actual
                 * time when the log rotated. We don't reverse the local time
                 * adjustment because, presumably, if you've specified local time
                 * logging you want the filenames to use local time.
                 */
                name = apr_psprintf(p, "%s.%" APR_TIME_T_FMT, name, apr_time_sec(log_time));
            }
        }

        if (rv = apr_file_open(&fd, name, xfer_flags, xfer_perms, p), APR_SUCCESS != rv) {
            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
                            "could not open transfer log file %s.", name);
            return NULL;
        }

        return fd;
    }
}
Example #17
0
static apr_status_t cached_explode(apr_time_exp_t *xt, apr_time_t t,
                                   struct exploded_time_cache_element *cache,
                                   int use_gmt)
{
    apr_int64_t seconds = apr_time_sec(t);
    struct exploded_time_cache_element *cache_element =
        &(cache[seconds & TIME_CACHE_MASK]);
    struct exploded_time_cache_element cache_element_snapshot;

    /* The cache is implemented as a ring buffer.  Each second,
     * it uses a different element in the buffer.  The timestamp
     * in the element indicates whether the element contains the
     * exploded time for the current second (vs the time
     * 'now - AP_TIME_RECENT_THRESHOLD' seconds ago).  If the
     * cached value is for the current time, we use it.  Otherwise,
     * we compute the apr_time_exp_t and store it in this
     * cache element. Note that the timestamp in the cache
     * element is updated only after the exploded time.  Thus
     * if two threads hit this cache element simultaneously
     * at the start of a new second, they'll both explode the
     * time and store it.  I.e., the writers will collide, but
     * they'll be writing the same value.
     */
    if (cache_element->t >= seconds) {
        /* There is an intentional race condition in this design:
         * in a multithreaded app, one thread might be reading
         * from this cache_element to resolve a timestamp from
         * TIME_CACHE_SIZE seconds ago at the same time that
         * another thread is copying the exploded form of the
         * current time into the same cache_element.  (I.e., the
         * first thread might hit this element of the ring buffer
         * just as the element is being recycled.)  This can
         * also happen at the start of a new second, if a
         * reader accesses the cache_element after a writer
         * has updated cache_element.t but before the writer
         * has finished updating the whole cache_element.
         *
         * Rather than trying to prevent this race condition
         * with locks, we allow it to happen and then detect
         * and correct it.  The detection works like this:
         *   Step 1: Take a "snapshot" of the cache element by
         *           copying it into a temporary buffer.
         *   Step 2: Check whether the snapshot contains consistent
         *           data: the timestamps at the start and end of
         *           the cache_element should both match the 'seconds'
         *           value that we computed from the input time.
         *           If these three don't match, then the snapshot
         *           shows the cache_element in the middle of an
         *           update, and its contents are invalid.
         *   Step 3: If the snapshot is valid, use it.  Otherwise,
         *           just give up on the cache and explode the
         *           input time.
         */
        memcpy(&cache_element_snapshot, cache_element,
               sizeof(struct exploded_time_cache_element));
        if ((seconds != cache_element_snapshot.t) ||
            (seconds != cache_element_snapshot.t_validate)) {
            /* Invalid snapshot */
            if (use_gmt) {
                return apr_time_exp_gmt(xt, t);
            }
            else {
                return apr_time_exp_lt(xt, t);
            }
        }
        else {
            /* Valid snapshot */
            memcpy(xt, &(cache_element_snapshot.xt),
                   sizeof(apr_time_exp_t));
        }
    }
    else {
        apr_status_t r;
        if (use_gmt) {
            r = apr_time_exp_gmt(xt, t);
        }
        else {
            r = apr_time_exp_lt(xt, t);
        }
        if (!APR_STATUS_IS_SUCCESS(r)) {
            return r;
        }
        cache_element->t = seconds;
        memcpy(&(cache_element->xt), xt, sizeof(apr_time_exp_t));
        cache_element->t_validate = seconds;
    }
    xt->tm_usec = (int)apr_time_usec(t);
    return APR_SUCCESS;
}
Example #18
0
static svn_error_t *
test_parse_date(const char **msg,
                svn_boolean_t msg_only,
                svn_test_opts_t *opts,
                apr_pool_t *pool)
{
  apr_time_t now, result;
  apr_time_exp_t nowexp, expt;
  svn_boolean_t matched;
  struct date_test *dt;
  const char **ft;

  *msg = "test svn_parse_date";

  if (msg_only)
    return SVN_NO_ERROR;

  now = apr_time_now();
  if (apr_time_exp_lt(&nowexp, now) != APR_SUCCESS)
    return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "Can't expand time");

  for (dt = localtz_tests; dt->str; dt++)
    {
      SVN_ERR(svn_parse_date(&matched, &result, dt->str, now, pool));
      if (!matched)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "Match failed for '%s'", dt->str);
      if (apr_time_exp_lt(&expt, result) != APR_SUCCESS)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "Expand failed for '%s'", dt->str);
      SVN_ERR(compare_results(dt, &expt));
    }

  for (dt = gmt_tests; dt->str; dt++)
    {
      SVN_ERR(svn_parse_date(&matched, &result, dt->str, now, pool));
      if (!matched)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "Match failed for '%s'", dt->str);
      if (apr_time_exp_gmt(&expt, result) != APR_SUCCESS)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "Expand failed for '%s'", dt->str);
      SVN_ERR(compare_results(dt, &expt));
    }

  for (dt = daytime_tests; dt->str; dt++)
    {
      SVN_ERR(svn_parse_date(&matched, &result, dt->str, now, pool));
      if (!matched)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "Match failed for '%s'", dt->str);
      if (apr_time_exp_lt(&expt, result) != APR_SUCCESS)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "Expand failed for '%s'", dt->str);
      dt->year = nowexp.tm_year + 1900;
      dt->mon = nowexp.tm_mon + 1;
      dt->mday = nowexp.tm_mday;
      SVN_ERR(compare_results(dt, &expt));
    }

  for (ft = failure_tests; *ft; ft++)
    {
      SVN_ERR(svn_parse_date(&matched, &result, *ft, now, pool));
      if (matched)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL, "Match succeeded for '%s'", *ft);
    }

  return SVN_NO_ERROR;
}
// Generate the actual cookie
void make_cookie(request_rec *r, char uid[], char cur_uid[], int use_dnt_expires)
{   // configuration
    cookietrack_settings_rec *dcfg;
    dcfg = ap_get_module_config(r->per_dir_config, &cookietrack_module);

    /* 1024 == hardcoded constant */
    char cookiebuf[1024];
    char *new_cookie;
    const char *rname = ap_get_remote_host(r->connection, r->per_dir_config,
                                           REMOTE_NAME, NULL);

    /* XXX: hmm, this should really tie in with mod_unique_id */
    apr_snprintf(cookiebuf, sizeof(cookiebuf), "%s", uid );

    if (dcfg->expires) {

        /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */
        new_cookie = apr_psprintf(r->pool, "%s=%s; path=/",
                                  dcfg->cookie_name, cookiebuf);

        if ((dcfg->style == CT_UNSET) || (dcfg->style == CT_NETSCAPE)) {
            apr_time_exp_t tms;
            apr_time_exp_gmt(&tms, r->request_time
                                 + apr_time_from_sec(dcfg->expires));

            // this sets a fixed expires in the future
            if( use_dnt_expires ) {
                new_cookie = apr_psprintf( r->pool,
                                "%s; expires=%s", new_cookie, dcfg->dnt_expires );

            // use the dynamic one
            } else {
                new_cookie = apr_psprintf( r->pool,
                                "%s; expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT",
                                new_cookie, apr_day_snames[tms.tm_wday],
                                tms.tm_mday,
                                apr_month_snames[tms.tm_mon],
                                tms.tm_year % 100,
                                tms.tm_hour, tms.tm_min, tms.tm_sec
                             );
            }
        } else {
            int expires = 0;

            // use a static expires date in the future
            if( use_dnt_expires ) {
                time_t t;
                time( &t );
                expires = dcfg->dnt_max_age - t;

            // use the dynamic one
            } else {
                expires = dcfg->expires;
            }

            _DEBUG && fprintf( stderr, "Expires = %d\n", expires );

            new_cookie = apr_psprintf( r->pool,
                                       "%s; max-age=%d",
                                       new_cookie,
                                       expires );
        }

    } else {
        new_cookie = apr_psprintf(r->pool, "%s=%s; path=/",
                                  dcfg->cookie_name, cookiebuf);
    }

    if (dcfg->cookie_domain != NULL) {
        new_cookie = apr_pstrcat(r->pool, new_cookie, "; domain=",
                                 dcfg->cookie_domain,
                                 (dcfg->style == CT_COOKIE2
                                  ? "; version=1"
                                  : ""),
                                 NULL);
    }

    // r->err_headers_out also honors non-2xx responses and
    // internal redirects. See the patch here:
    // http://svn.apache.org/viewvc?view=revision&revision=1154620
    apr_table_addn( r->err_headers_out,
                    (dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"),
                    new_cookie );

    // we also set it on the INCOMING cookie header, so the app can
    // Just Use It without worrying. Only do so if we don't already
    // have an incoming cookie value, or it will send 2 cookies with
    // the same name, with both the old and new value :(
    if( !cur_uid ) {
        apr_table_addn( r->headers_in, "Cookie",  new_cookie );
    }

    // Set headers? We set both incoming AND outgoing:
    if( dcfg->send_header ) {
        // incoming
        apr_table_addn( r->headers_in,
                        dcfg->header_name,
                        apr_pstrdup(r->pool, uid) );

        // outgoing
        apr_table_addn( r->err_headers_out,
                        dcfg->header_name,
                        apr_pstrdup(r->pool, uid) );
    }

    // set a note, so we can capture it in the logs
    // this expects chars, and apr_pstrdup will make sure any char stays
    // in scope for the function. If not, it ends up being empty.
    apr_table_setn( r->notes, dcfg->note_name, apr_pstrdup(r->pool, uid) );

}
Example #20
0
SWITCH_DECLARE(switch_status_t) switch_time_exp_gmt(switch_time_exp_t *result, switch_time_t input)
{
	return apr_time_exp_gmt((apr_time_exp_t *) result, input);
}
/*
 * Open a new log file, and if successful
 * also close the old one.
 *
 * The timestamp for the calculation of the file
 * name of the new log file will be the actual millisecond
 * timestamp, except when a regular rotation based on a time
 * interval is configured and the previous interval
 * is over. Then the timestamp is the starting time
 * of the actual interval.
 */
static void doRotate(rotate_config_t *config, rotate_status_t *status)
{

    int now = get_now(config);
    int tLogStart;
    apr_status_t rv;
    struct logfile newlog;
    int thisLogNum = -1;

    status->rotateReason = ROTATE_NONE;

    if (config->tRotation) {
        int tLogEnd;
        tLogStart = (now / config->tRotation) * config->tRotation;
        tLogEnd = tLogStart + config->tRotation;
        /*
         * Check if rotation was forced and the last rotation
         * interval is not yet over. Use the value of now instead
         * of the time interval boundary for the file name then.
         */
        if (tLogStart < status->tLogEnd) {
            tLogStart = now;
        }
        status->tLogEnd = tLogEnd;
    }
    else {
        tLogStart = now;
    }

    if (config->use_strftime) {
        apr_time_t tNow = apr_time_from_sec(tLogStart);
        apr_time_exp_t e;
        apr_size_t rs;

        apr_time_exp_gmt(&e, tNow);
        apr_strftime(newlog.name, &rs, sizeof(newlog.name), config->szLogRoot, &e);
    }
    else {
        if (config->truncate) {
            apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot);
        }
        else if (config->num_files > 0) { 
            if (status->fileNum == -1 || status->fileNum == (config->num_files - 1)) {
                thisLogNum = 0;
                apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot);
            }
            else { 
                thisLogNum = status->fileNum + 1;
                apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%d", config->szLogRoot, thisLogNum);
            }
        }
        else {
            apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%010d", config->szLogRoot,
                         tLogStart);
        }
    }
    apr_pool_create(&newlog.pool, status->pool);
    if (config->verbose) {
        fprintf(stderr, "Opening file %s\n", newlog.name);
    }
    rv = apr_file_open(&newlog.fd, newlog.name, APR_WRITE | APR_CREATE | APR_APPEND
                       | (config->truncate || (config->num_files > 0 && status->current.fd) ? APR_TRUNCATE : 0), 
                       APR_OS_DEFAULT, newlog.pool);
    if (rv == APR_SUCCESS) {
        /* Handle post-rotate processing. */
        post_rotate(newlog.pool, &newlog, config, status);

        status->fileNum = thisLogNum;
        /* Close out old (previously 'current') logfile, if any. */
        if (status->current.fd) {
            close_logfile(config, &status->current);
        }

        /* New log file is now 'current'. */
        status->current = newlog;
    }
    else {
        char error[120];

        apr_strerror(rv, error, sizeof error);

        /* Uh-oh. Failed to open the new log file. Try to clear
         * the previous log file, note the lost log entries,
         * and keep on truckin'. */
        if (status->current.fd == NULL) {
            fprintf(stderr, "Could not open log file '%s' (%s)\n", newlog.name, error);
            exit(2);
        }

        /* Throw away new state; it isn't going to be used. */
        apr_pool_destroy(newlog.pool);

        /* Try to keep this error message constant length
         * in case it occurs several times. */
        apr_snprintf(status->errbuf, sizeof status->errbuf,
                     "Resetting log file due to error opening "
                     "new log file, %10d messages lost: %-25.25s\n",
                     status->nMessCount, error);

        truncate_and_write_error(status);
    }

    status->nMessCount = 0;
}
/* Given a mod_dav_svn @a resource, set @a *timeval and @a *datestring
   to the last-modified-time of the resource.  The datestring will be
   formatted according to @a format.  Use @a pool for both
   scratchwork, and to allocate @a *datestring.

   If @a timeval or @a datestring is NULL, don't touch it.

   Return zero on success, non-zero if an error occurs. */
static int
get_last_modified_time(const char **datestring,
                       apr_time_t *timeval,
                       const dav_resource *resource,
                       enum time_format format,
                       apr_pool_t *pool)
{
  svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
  svn_string_t *committed_date = NULL;
  svn_error_t *serr;
  apr_time_t timeval_tmp;

  if ((datestring == NULL) && (timeval == NULL))
    return 0;

  if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION)
    {
      /* A baseline URI. */
      committed_rev = resource->info->root.rev;
    }
  else if (resource->type == DAV_RESOURCE_TYPE_REGULAR
           || resource->type == DAV_RESOURCE_TYPE_WORKING
           || resource->type == DAV_RESOURCE_TYPE_VERSION)
    {
      serr = svn_fs_node_created_rev(&committed_rev,
                                     resource->info->root.root,
                                     resource->info->repos_path, pool);
      if (serr != NULL)
        {
          svn_error_clear(serr);
          return 1;
        }
    }
  else
    {
      /* unsupported resource kind -- has no mod-time */
      return 1;
    }

  serr = get_path_revprop(&committed_date,
                          resource,
                          committed_rev,
                          SVN_PROP_REVISION_DATE,
                          pool);
  if (serr)
    {
      svn_error_clear(serr);
      return 1;
    }

  if (committed_date == NULL)
    return 1;

  /* return the ISO8601 date as an apr_time_t */
  serr = svn_time_from_cstring(&timeval_tmp, committed_date->data, pool);
  if (serr != NULL)
    {
      svn_error_clear(serr);
      return 1;
    }

  if (timeval)
    memcpy(timeval, &timeval_tmp, sizeof(*timeval));

  if (! datestring)
    return 0;

  if (format == time_format_iso8601)
    {
      *datestring = committed_date->data;
    }
  else if (format == time_format_rfc1123)
    {
      apr_time_exp_t tms;
      apr_status_t status;

      /* convert the apr_time_t into an apr_time_exp_t */
      status = apr_time_exp_gmt(&tms, timeval_tmp);
      if (status != APR_SUCCESS)
        return 1;

      /* stolen from dav/fs/repos.c   :-)  */
      *datestring = apr_psprintf(pool, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT",
                                 apr_day_snames[tms.tm_wday],
                                 tms.tm_mday, apr_month_snames[tms.tm_mon],
                                 tms.tm_year + 1900,
                                 tms.tm_hour, tms.tm_min, tms.tm_sec);
    }
  else /* unknown time format */
    {
      return 1;
    }

  return 0;
}
// See here for the structure of request_rec:
// http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html
static int hook(request_rec *r)
{
    settings_rec *cfg = ap_get_module_config( r->per_dir_config,
                                              &querystring2cookie_module );

    /* Do not run in subrequests, don't run if not enabled */
    if( !(cfg->enabled || r->main) ) {
        return DECLINED;
    }

    /* No query string? nothing to do here */
    if( !(r->args) || strlen( r->args ) < 1 ) {
        return DECLINED;
    }

    /* skip if dnt headers are present? */
    if( !(cfg->enabled_if_dnt) && apr_table_get( r->headers_in, "DNT" ) ) {
        _DEBUG && fprintf( stderr, "DNT header sent: declined\n" );
        return DECLINED;
    }

    _DEBUG && fprintf( stderr, "Query string: '%s'\n", r->args );

    // ***********************************
    // Calculate expiry time
    // ***********************************

    // The expiry time. We can't use max-age because IE6 - IE8 do not
    // support it :(
    char *expires = "";

    if( cfg->cookie_expires > 0 ) {

        apr_time_exp_t tms;
        apr_time_exp_gmt( &tms, r->request_time
                              + apr_time_from_sec( cfg->cookie_expires ) );

        expires = apr_psprintf( r->pool,
                            "expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT",
                            apr_day_snames[tms.tm_wday],
                            tms.tm_mday,
                            apr_month_snames[tms.tm_mon],
                            tms.tm_year % 100,
                            tms.tm_hour, tms.tm_min, tms.tm_sec
                        );
    }

    // ***********************************
    // Find key/value pairs
    // ***********************************

    // keep track of how much data we've been writing - there's a limit to how
    // much a browser will store per domain (usually 4k) so we want to make sure
    // it's not getting flooded.
    int total_pair_size = 0;

    // This holds the final cookie we'll send back - make sure to initialize
    // or it can point at garbage!
    char *cookie = "";

    // string to use as the cookie name (together with the prefix) - make sure to
    // initialize or it can point at garbage!
    char *cookie_name = "";

    // Iterate over the key/value pairs
    char *last_pair;
    char *pair = apr_strtok( apr_pstrdup( r->pool, r->args ), "&", &last_pair );

    _DEBUG && fprintf( stderr, "about to parse query string for pairs\n" );

    _DEBUG && fprintf( stderr, "looking for cookie name in %s\n", cfg->cookie_name_from );

    while( pair != NULL ) {

        // length of the substr before the = sign (or index of the = sign)
        int contains_equals_at = strcspn( pair, "=" );

        // Does not contains a =, or starts with a =, meaning it's garbage
        if( !strstr(pair, "=") || contains_equals_at < 1 ) {
            _DEBUG && fprintf( stderr, "invalid pair: %s\n", pair );

            // And get the next pair -- has to be done at every break
            pair = apr_strtok( NULL, "&", &last_pair );
            continue;
        }

        _DEBUG && fprintf( stderr, "pair looks valid: %s - = sign at pos: %i\n",
                            pair, contains_equals_at );

        // So this IS a key value pair. Let's get the key and the value.
        // first, get the key - everything up to the first =
        char *key   = apr_pstrndup( r->pool, pair, contains_equals_at );

        // now get the value, everything AFTER the = sign. We do that by
        // moving the pointer past the = sign.
        char *value = apr_pstrdup( r->pool, pair );
        value += contains_equals_at + 1;

        _DEBUG && fprintf( stderr, "pair=%s, key=%s, value=%s\n", pair, key, value );

        // you want us to use a name from the query string?
        // This might be that name.
        if( cfg->cookie_name_from && !(strlen(cookie_name)) &&
            strcasecmp( key, cfg->cookie_name_from ) == 0
        ) {
            // get everything after the = sign -- that's our name.
            cookie_name = apr_pstrcat( r->pool, cfg->cookie_prefix, value, NULL );

            _DEBUG && fprintf( stderr, "using %s as the cookie name\n", cookie_name );

            // And get the next pair -- has to be done at every break
            pair = apr_strtok( NULL, "&", &last_pair );
            continue;

        // may be on the ignore list
        } else {

            // may have to continue the outer loop, use this as a marker
            int do_continue = 0;

            // you might have blacklisted this key; let's check
            // Following tutorial code here again:
            // http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html
            int i;
            for( i = 0; i < cfg->qs_ignore->nelts; i++ ) {

                char *ignore = ((char **)cfg->qs_ignore->elts)[i];

                _DEBUG && fprintf( stderr, "processing ignore %s against pair %s\n",
                                        ignore, pair );

                // it's indeed on the ignore list; move on
                // do this by comparing the string length first - if the length of
                // the ignore key and the key are identical AND the first N characters
                // of the string are the same
                if( strcasecmp( key, ignore ) == 0 ) {
                    _DEBUG && fprintf( stderr, "pair %s is on the ignore list: %s\n",
                                        pair, ignore );

                    // signal to continue the outer loop; we found an ignore match
                    do_continue = 1;
                    break;
                }
            }

            // ignore match found, move on
            if( do_continue ) {
                // And get the next pair -- has to be done at every break
                pair = apr_strtok( NULL, "&", &last_pair );
                continue;
            }
        }

        // looks like a valid key=value declaration
        _DEBUG && fprintf( stderr, "valid key/value pair: %s\n", pair );

        // Now, the key may contain URL unsafe characters, which are also
        // not allowed in Cookies. See here:
        // http://tools.ietf.org/html/rfc2068, section 2.2 on 'tspecials'
        //
        // So instead, we url encode the key. The size of the key is max
        // 3 times old key size (any char gets encoded into %xx), so allow
        // for that space. See the documentation here:
        // http://httpd.apache.org/apreq/docs/libapreq2/apreq__util_8h.html#785be2ceae273b0a7b2ffda223b2ebae
        char *escaped_key   = apreq_escape( r->pool, key, strlen(key) );
        char *escaped_value = apreq_escape( r->pool, value, strlen(value) );

        _DEBUG && fprintf( stderr, "Original key: %s - Escaped key: %s\n", key, escaped_key );
        _DEBUG && fprintf( stderr, "Original value: %s - Escaped value: %s\n", value, escaped_value );

        // Now, let's do some transposing: The '=' sign needs to be replaced
        // with whatever the separator is. It can't be a '=' sign, as that's
        // illegal in cookies. The string may be larger than a single char,
        // so split the string and do the magix.

        // This makes key[delim]value - redefining pair here is safe, we're
        // just using it for printing now.
        char *key_value = apr_pstrcat( r->pool,
                                       escaped_key,
                                       cfg->cookie_key_value_delimiter,
                                       escaped_value,
                                       NULL
                                    );

        int this_pair_size = strlen( key_value );

        // Make sure the individual pair, as well as the whole thing doesn't
        // get too long

        _DEBUG && fprintf( stderr,
                "this pair size: %i, total pair size: %i, max size: %i\n",
                this_pair_size, total_pair_size, cfg->cookie_max_size  );

        if( (this_pair_size <= cfg->cookie_max_size) &&
            (total_pair_size + this_pair_size <= cfg->cookie_max_size)
        ) {

            cookie = apr_pstrcat( r->pool,
                                  cookie,       // the cookie so far
                                  // If we already have pairs in here, we need the
                                  // delimiter, otherwise we don't.
                                  (strlen(cookie) ? cfg->cookie_pair_delimiter : ""),
                                  key_value,    // the next pair.
                                  NULL
                            );

            // update the book keeping - this is the new size including delims
            total_pair_size = strlen(cookie);

            _DEBUG && fprintf( stderr, "this pair size: %i, total pair size: %i\n",
                                    this_pair_size, total_pair_size );

        } else {
            _DEBUG && fprintf( stderr,
                "Pair size too long to add: %s (this: %i total: %i max: %i)\n",
                key_value, this_pair_size, total_pair_size, cfg->cookie_max_size );
        }

        // and move the pointer
        pair = apr_strtok( NULL, "&", &last_pair );
    }

     // So you told us we should use a cookie name from the query string,
     // but we never found it in there. That's a problem.
     if( cfg->cookie_name_from && !strlen(cookie_name) ) {

         // r->err_headers_out also honors non-2xx responses and
         // internal redirects. See the patch here:
         // http://svn.apache.org/viewvc?view=revision&revision=1154620
         apr_table_addn( r->err_headers_out,
             "X-QS2Cookie",
             apr_pstrcat( r->pool,
                 "ERROR: Did not detect cookie name - missing QS argument: ",
                 cfg->cookie_name_from,
                 NULL
             )
         );

     // Let's return the output
     } else {

         // we got here without a cookie name? We can use the default.
         if( !strlen(cookie_name) ) {
             _DEBUG && fprintf( stderr, "explicitly setting cookie name to: %s\n",
                                         cfg->cookie_name );

             cookie_name = apr_pstrcat( r->pool,
                                        cfg->cookie_prefix, cfg->cookie_name,
                                        NULL );
         }

         _DEBUG && fprintf( stderr, "cookie name: %s\n", cookie_name );

        // XXX use a sprintf format for more flexibility?
        if( cfg->encode_in_key ) {
            _DEBUG && fprintf( stderr, "%s: encoding in the key\n", cookie_name );

            cookie = apr_pstrcat( r->pool,
                            // cookie data
                            cookie_name, cfg->cookie_pair_delimiter, cookie, "=",
                            // The format is different on 32 (%ld) vs 64bit (%lld), so
                            // use the constant for it instead. You can find this in apr.h
                            apr_psprintf( r->pool, "%" APR_OFF_T_FMT, apr_time_sec(apr_time_now()) ),
                            NULL
                         );
        } else {
            _DEBUG && fprintf( stderr, "%s: encoding in the value\n", cookie_name );
            cookie = apr_pstrcat( r->pool, cookie_name, "=", cookie, NULL );

        }

        // And now add the meta data to the cookie
        cookie = apr_pstrcat( r->pool, cookie, "; ",
                                "path=/; ", cfg->cookie_domain, expires,
                                NULL );

        _DEBUG && fprintf( stderr, "cookie: %s\n", cookie );

        // r->err_headers_out also honors non-2xx responses and
        // internal redirects. See the patch here:
        // http://svn.apache.org/viewvc?view=revision&revision=1154620
        apr_table_addn( r->err_headers_out, "Set-Cookie", cookie );
    }

    return OK;
}