Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Faster HTTP date parsing #4

Merged
merged 5 commits into from

2 participants

@johnezang

Time (in us) for +dateFromHttpDateString:-
... before this commit: 69.439us.
... after this commit   :  2.993us, over 22x faster.

johnezang added some commits
@johnezang johnezang Fix bug in the date strings that the unit test creates.
Per [RFC 2616, section 3.3.1](http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1)-

> All HTTP date/time stamps MUST be represented in Greenwich Mean Time (GMT), without exception.

Prior to this commit, the dates being created were in the systems local timezone.
bae505f
@johnezang johnezang Significantly improve the performance of parsing HTTP dates.
Time (in us) for `+dateFromHttpDateString:`-
... before this commit: 69.439us.
... after this commit :  2.993us, over 22x faster.
9c26484
@johnezang johnezang Minor tidies. 5891bc4
@johnezang johnezang Minor tidies. 4de3d44
@johnezang johnezang Clean up and add a few compiler warning flags. e1864af
@steipete
Owner

Awesome, thank you John!

Can you shortly explain how you created those tables? I totally will merge this, but I'd love to understand it :)

Ragel. Below is the ragel source I used. I then polished / pretty-printed and tweaked the output from ragel. Compiled with:

shell% ragel -F1 http-date.rl
shell% gcc -o http-date http-date.c
shell% ./http-date 'Sun, 06 Nov 1994 08:49:37 GMT' 'Sunday, 06-Nov-94 08:49:37 GMT' 'Sun Nov  6 08:49:37 1994' 'Sat Dec 24 14:34:26 2037' 'Sunday, 06-Nov-94 08:49:37 GMT' 'Sun, 06 Nov 1994 08:49:37 GMT'
// http-date.rl

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

%%{
    machine httpDate;

    yearDigit   = ( [0-9] @{ gdate.year   = gdate.year   * 10   + (fc - '0'); });
    dayDigit    = ( [0-9] @{ gdate.day    = gdate.day    * 10   + (fc - '0'); });
    hourDigit   = ( [0-9] @{ gdate.hour   = gdate.hour   * 10   + (fc - '0'); });
    minuteDigit = ( [0-9] @{ gdate.minute = gdate.minute * 10   + (fc - '0'); });
    secondDigit = ( [0-9] @{ gdate.second = gdate.second * 10.0 + (fc - '0'); });

    wkday        = ("Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun");
    weekday      = ("Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday");
    month        = (("Jan" @{ gdate.month =  1; }) | ("Feb" @{ gdate.month =  2; }) | ("Mar" @{ gdate.month =  3; }) |
                    ("Apr" @{ gdate.month =  4; }) | ("May" @{ gdate.month =  5; }) | ("Jun" @{ gdate.month =  6; }) |
                    ("Jul" @{ gdate.month =  7; }) | ("Aug" @{ gdate.month =  8; }) | ("Sep" @{ gdate.month =  9; }) |
                    ("Oct" @{ gdate.month = 10; }) | ("Nov" @{ gdate.month = 11; }) | ("Dec" @{ gdate.month = 12; }));

    year4Digits   = (yearDigit . yearDigit . yearDigit . yearDigit);
    year2Digits   = ((yearDigit . yearDigit) @{ gdate.year += 1900; });
    dayDigits     = (dayDigit . dayDigit);
    hourDigits    = (hourDigit . hourDigit);
    minuteDigits  = (minuteDigit . minuteDigit);
    secondDigits  = (secondDigit . secondDigit);

    date1        = (dayDigits  . " " . month . " " . year4Digits);
    date2        = (dayDigits  . "-" . month . "-" . year2Digits);
    date3        = (month      . " " . (dayDigits | " " . dayDigit));
    time         = (hourDigits . ":" . minuteDigits . ":" . secondDigits);

    rfc1123date  = (wkday   . "," . " " . date1 . " " . time . " " . "GMT");
    rfc850date   = (weekday . "," . " " . date2 . " " . time . " " . "GMT");
    asctimedate  = (wkday   . " "       . date3 . " " . time . " " . year4Digits);

    HTTPdate    = ((rfc1123date %{ parsed = 1; }) | (rfc850date %{ parsed = 1; }) | (asctimedate %{ parsed = 1; }));

    main := HTTPdate;
}%%

%% write data nofinal;

typedef signed char SInt8;
typedef signed int SInt32;

struct __gdate {
    SInt32 year;
    SInt8 month;
    SInt8 day;
    SInt8 hour;
    SInt8 minute;
    double second;
};
typedef struct __gdate __gdate;

void scanner(char *buf) {
    int cs;

    int parsed = 0;
    __gdate gdate;
    memset(&gdate, 0, sizeof(__gdate));

    %% write init;

    {
        int len = strlen(buf);
        char *p = buf, *pe = p + len, *eof = pe;

        %% write exec;
    }

    printf("parsed: %d, %d/%d/%d %d:%d:%.2f\n", parsed, gdate.month, gdate.day, gdate.year, gdate.hour, gdate.minute, gdate.second);
}


int main(int argc, char *argv[]) {
  if(argc > 1) { int x; for(x = 1; x < argc; x++) { scanner(argv[x]); printf("-----\n");   }}
    return 0;
}
Owner

Great, thanks! We should probably commit this code too, since the tables generated from the state machines are pretty un-debug-able.
What's a good way to add this? As a comment?

As a comment probably makes the most sense, all things considered.

@steipete steipete merged commit f8cf070 into steipete:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 24, 2011
  1. @johnezang

    Fix bug in the date strings that the unit test creates.

    johnezang authored
    Per [RFC 2616, section 3.3.1](http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1)-
    
    > All HTTP date/time stamps MUST be represented in Greenwich Mean Time (GMT), without exception.
    
    Prior to this commit, the dates being created were in the systems local timezone.
  2. @johnezang

    Significantly improve the performance of parsing HTTP dates.

    johnezang authored
    Time (in us) for `+dateFromHttpDateString:`-
    ... before this commit: 69.439us.
    ... after this commit :  2.993us, over 22x faster.
  3. @johnezang

    Minor tidies.

    johnezang authored
  4. @johnezang

    Minor tidies.

    johnezang authored
  5. @johnezang
This page is out of date. Refresh to see the latest.
Showing with 260 additions and 61 deletions.
  1. +241 −43 SDURLCache.m
  2. +18 −18 SDURLCache.xcodeproj/project.pbxproj
  3. +1 −0  SDURLCacheTests.m
View
284 SDURLCache.m
@@ -27,22 +27,242 @@
#define kAFURLCachePath @"SDNetworkingURLCache"
#define kAFURLCacheMaintenanceTime 5ull
-static NSTimeInterval const kAFURLCacheInfoDefaultMinCacheInterval = 5 * 60; // 5 minute
+static NSTimeInterval const kAFURLCacheInfoDefaultMinCacheInterval = 5.0 * 60.0; // 5 minute
static NSString *const kAFURLCacheInfoFileName = @"cacheInfo.plist";
static NSString *const kAFURLCacheInfoDiskUsageKey = @"diskUsage";
static NSString *const kAFURLCacheInfoAccessesKey = @"accesses";
static NSString *const kAFURLCacheInfoSizesKey = @"sizes";
static float const kAFURLCacheLastModFraction = 0.1f; // 10% since Last-Modified suggested by RFC2616 section 13.2.4
-static float const kAFURLCacheDefault = 3600; // Default cache expiration delay if none defined (1 hour)
-
-static NSDateFormatter* CreateDateFormatter(NSString *format) {
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
- [dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease]];
- [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
- [dateFormatter setDateFormat:format];
- return dateFormatter;
+static float const kAFURLCacheDefault = 3600.0f; // Default cache expiration delay if none defined (1 hour)
+
+
+static const char _httpDate_trans_keys[] = {
+ 0, 0, 70, 87, 114, 114, 105, 105, 32, 100, 65, 83, 112, 117, 114, 114, 32,
+ 32, 32, 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57,
+ 58, 58, 48, 57, 48, 57, 32, 32, 48, 57, 48, 57, 48, 57, 48, 57, 103,
+ 103, 101, 101, 99, 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97,
+ 114, 121, 111, 111, 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 32, 32, 48,
+ 57, 48, 57, 32, 32, 65, 83, 112, 117, 114, 114, 32, 32, 48, 57, 48, 57,
+ 48, 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57, 58,
+ 58, 48, 57, 48, 57, 32, 32, 71, 71, 77, 77, 84, 84, 103, 103, 101, 101,
+ 99, 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97, 114, 121, 111,
+ 111, 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 97, 97, 121, 121, 44, 44,
+ 32, 32, 48, 57, 48, 57, 45, 45, 65, 83, 112, 117, 114, 114, 45, 45, 48,
+ 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57, 58, 58,
+ 48, 57, 48, 57, 32, 32, 71, 71, 77, 77, 84, 84, 103, 103, 101, 101, 99,
+ 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97, 114, 121, 111, 111,
+ 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 111, 111, 110, 110, 97, 117, 116,
+ 116, 32, 117, 114, 114, 100, 100, 104, 117, 117, 117, 32, 114, 115, 115, 101, 101,
+ 32, 115, 101, 101, 100, 100, 32, 110, 101, 101, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const char _httpDate_key_spans[] = {
+ 0, 18, 1, 1, 69, 19, 6, 1, 1, 26, 10, 1, 10, 10, 1, 10, 10,
+ 1, 10, 10, 1, 10, 10, 10, 10, 1, 1, 1, 1, 1, 21, 1, 3, 1,
+ 8, 1, 1, 1, 1, 1, 1, 1, 10, 10, 1, 19, 6, 1, 1, 10, 10,
+ 10, 10, 1, 10, 10, 1, 10, 10, 1, 10, 10, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 21, 1, 3, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 10, 10, 1, 19, 6, 1, 1, 10, 10, 1, 10, 10, 1, 10, 10, 1,
+ 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 1, 3, 1, 8, 1,
+ 1, 1, 1, 1, 1, 1, 1, 21, 1, 86, 1, 1, 14, 1, 83, 1, 1,
+ 84, 1, 1, 79, 1, 0, 0, 0
+};
+
+static const short _httpDate_index_offsets[] = {
+ 0, 0, 19, 21, 23, 93, 113, 120, 122, 124, 151, 162, 164, 175, 186, 188, 199,
+ 210, 212, 223, 234, 236, 247, 258, 269, 280, 282, 284, 286, 288, 290, 312, 314, 318,
+ 320, 329, 331, 333, 335, 337, 339, 341, 343, 354, 365, 367, 387, 394, 396, 398, 409,
+ 420, 431, 442, 444, 455, 466, 468, 479, 490, 492, 503, 514, 516, 518, 520, 522, 524,
+ 526, 528, 530, 532, 554, 556, 560, 562, 571, 573, 575, 577, 579, 581, 583, 585, 587,
+ 589, 591, 602, 613, 615, 635, 642, 644, 646, 657, 668, 670, 681, 692, 694, 705, 716,
+ 718, 729, 740, 742, 744, 746, 748, 750, 752, 754, 756, 758, 780, 782, 786, 788, 797,
+ 799, 801, 803, 805, 807, 809, 811, 813, 835, 837, 924, 926, 928, 943, 945, 1029, 1031,
+ 1033, 1118, 1120, 1122, 1202, 1204, 1205, 1206
+};
+
+static const unsigned char _httpDate_indicies[] = {
+ 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 4, 1, 1,
+ 5, 1, 6, 1, 7, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 10, 1, 11, 1, 1, 12, 1, 13, 1, 1, 1,
+ 14, 1, 1, 15, 16, 17, 1, 1, 1, 18, 1, 19, 1, 1, 1, 1, 20,
+ 1, 21, 1, 22, 1, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 1, 26, 1, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 1, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 1, 29,
+ 1, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 1, 32, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 1, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 1, 35, 1, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 1, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 1, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 1, 40, 1, 41, 1, 42, 1, 43, 1, 44,
+ 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 46, 1, 47, 1, 48, 1, 49, 1, 50, 1, 51, 1, 1,
+ 1, 1, 1, 1, 52, 1, 53, 1, 54, 1, 55, 1, 56, 1, 57, 1, 58,
+ 1, 59, 1, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 1, 61, 61, 61,
+ 61, 61, 61, 61, 61, 61, 61, 1, 62, 1, 63, 1, 1, 64, 1, 65, 1,
+ 1, 1, 66, 1, 1, 67, 68, 69, 1, 1, 1, 70, 1, 71, 1, 1, 1,
+ 1, 72, 1, 73, 1, 74, 1, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 1, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 1, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 1, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 1,
+ 79, 1, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 1, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 1, 82, 1, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 1, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 1, 85, 1, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 1, 87, 87, 87, 87, 87, 87, 87,
+ 87, 87, 87, 1, 88, 1, 89, 1, 90, 1, 91, 1, 92, 1, 93, 1, 94,
+ 1, 95, 1, 96, 1, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 98, 1, 99, 1, 100, 1, 101, 1, 102,
+ 1, 103, 1, 1, 1, 1, 1, 1, 104, 1, 105, 1, 106, 1, 107, 1, 108,
+ 1, 109, 1, 110, 1, 111, 1, 112, 1, 113, 1, 114, 1, 115, 115, 115, 115,
+ 115, 115, 115, 115, 115, 115, 1, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+ 1, 117, 1, 118, 1, 1, 119, 1, 120, 1, 1, 1, 121, 1, 1, 122, 123,
+ 124, 1, 1, 1, 125, 1, 126, 1, 1, 1, 1, 127, 1, 128, 1, 129, 1,
+ 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 1, 131, 131, 131, 131, 131, 131,
+ 131, 131, 131, 131, 1, 132, 1, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133,
+ 1, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 1, 135, 1, 136, 136, 136,
+ 136, 136, 136, 136, 136, 136, 136, 1, 137, 137, 137, 137, 137, 137, 137, 137, 137,
+ 137, 1, 138, 1, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 1, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140, 1, 141, 1, 142, 1, 143, 1, 144, 1,
+ 145, 1, 146, 1, 147, 1, 148, 1, 149, 1, 150, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 151, 1, 152, 1,
+ 153, 1, 154, 1, 155, 1, 156, 1, 1, 1, 1, 1, 1, 157, 1, 158, 1,
+ 159, 1, 160, 1, 161, 1, 162, 1, 163, 1, 164, 1, 7, 1, 165, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 164, 1, 166, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 167, 1, 168, 1, 10, 1, 169, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 170, 1, 171, 1, 8, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 172, 1, 168, 1, 173, 1, 8, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 168, 1, 174, 1, 175, 1,
+ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 176, 1, 172, 1, 1, 1, 1,
+ 0
+};
+
+static const unsigned char _httpDate_trans_targs[] = {
+ 2, 0, 124, 126, 131, 137, 3, 4, 5, 41, 82, 6, 26, 28, 30, 33, 35,
+ 37, 39, 7, 25, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 141, 8, 27, 8, 29, 8, 31, 32, 8, 8, 8, 34,
+ 8, 8, 36, 8, 38, 8, 40, 8, 42, 43, 44, 45, 46, 67, 69, 71, 74,
+ 76, 78, 80, 47, 66, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 142, 48, 68, 48, 70, 48, 72, 73, 48, 48, 48,
+ 75, 48, 48, 77, 48, 79, 48, 81, 48, 83, 84, 85, 86, 87, 88, 89, 90,
+ 109, 111, 113, 116, 118, 120, 122, 91, 108, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 143, 92, 110, 92, 112, 92, 114, 115, 92,
+ 92, 92, 117, 92, 92, 119, 92, 121, 92, 123, 92, 125, 127, 128, 129, 130, 132,
+ 135, 133, 134, 136, 138, 139, 140
+};
+
+static const char _httpDate_trans_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 2, 2, 0, 3, 3, 0, 4, 4, 0, 5,
+ 5, 0, 6, 6, 6, 6, 7, 0, 8, 0, 9, 0, 0, 10, 11, 12, 0,
+ 13, 14, 0, 15, 0, 16, 0, 17, 0, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 6, 6, 6, 6, 0, 3, 3, 0, 4, 4,
+ 0, 5, 5, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0, 0, 10, 11, 12,
+ 0, 13, 14, 0, 15, 0, 16, 0, 17, 0, 0, 0, 0, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 6, 18, 0, 3, 3, 0,
+ 4, 4, 0, 5, 5, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0, 0, 10,
+ 11, 12, 0, 13, 14, 0, 15, 0, 16, 0, 17, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
+};
+
+static const char _httpDate_eof_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 19, 20, 21
+};
+
+static NSDate *_parseHTTPDate(const char *buf, size_t bufLen) {
+ const char *p = buf, *pe = p + bufLen, *eof = pe;
+ int parsed = 0, cs = 1;
+ NSDate *date = NULL;
+
+ CFGregorianDate gdate;
+ memset(&gdate, 0, sizeof(CFGregorianDate));
+
+ {
+ int _slen, _trans;
+ const char *_keys;
+ const unsigned char *_inds;
+ if(p == pe) { goto _test_eof; }
+ _resume:
+ _keys = _httpDate_trans_keys + (cs << 1);
+ _inds = _httpDate_indicies + _httpDate_index_offsets[cs];
+ _slen = _httpDate_key_spans[cs];
+ _trans = _inds[(_slen > 0) && (_keys[0] <= (*p)) && ((*p) <= _keys[1]) ? (*p) - _keys[0] : _slen];
+ cs = _httpDate_trans_targs[_trans];
+
+ if(_httpDate_trans_actions[_trans] == 0) { goto _again; }
+
+ switch(_httpDate_trans_actions[_trans]) {
+ case 6: gdate.year = gdate.year * 10 + ((*p) - '0'); break;
+ case 18: gdate.year = gdate.year * 10 + ((*p) - '0'); gdate.year += 1900; break;
+ case 10: gdate.month = 1; break;
+ case 9: gdate.month = 2; break;
+ case 13: gdate.month = 3; break;
+ case 1: gdate.month = 4; break;
+ case 14: gdate.month = 5; break;
+ case 12: gdate.month = 6; break;
+ case 11: gdate.month = 7; break;
+ case 7: gdate.month = 8; break;
+ case 17: gdate.month = 9; break;
+ case 16: gdate.month = 10; break;
+ case 15: gdate.month = 11; break;
+ case 8: gdate.month = 12; break;
+ case 2: gdate.day = gdate.day * 10 + ((*p) - '0'); break;
+ case 3: gdate.hour = gdate.hour * 10 + ((*p) - '0'); break;
+ case 4: gdate.minute = gdate.minute * 10 + ((*p) - '0'); break;
+ case 5: gdate.second = gdate.second * 10.0 + ((*p) - '0'); break;
+ }
+
+ _again:
+ if( cs == 0) { goto _out; }
+ if(++p != pe) { goto _resume; }
+ _test_eof: {}
+ if(p == eof) {
+ switch(_httpDate_eof_actions[cs]) {
+ case 19: parsed = 1; break;
+ case 20: parsed = 1; break;
+ case 21: parsed = 1; break;
+ }
+ }
+
+ _out: {}
+ }
+
+ static CFTimeZoneRef gmtTimeZone;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{ gmtTimeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0); });
+
+ if(parsed == 1) { date = [NSDate dateWithTimeIntervalSinceReferenceDate:CFGregorianDateGetAbsoluteTime(gdate, gmtTimeZone)]; }
+
+ return(date);
}
+
@implementation NSCachedURLResponse(NSCoder)
#pragma clang diagnostic push
@@ -109,15 +329,6 @@ + (NSString *)cacheKeyForURL:(NSURL *)url {
#pragma mark SDURLCache (private)
-static dispatch_queue_t get_date_formatter_queue() {
- static dispatch_queue_t _dateFormatterQueue;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- _dateFormatterQueue = dispatch_queue_create("com.petersteinberger.disk-cache.dateformatter", NULL);
- });
- return _dateFormatterQueue;
-}
-
static dispatch_queue_t get_disk_cache_queue() {
static dispatch_once_t onceToken;
static dispatch_queue_t _diskCacheQueue;
@@ -165,30 +376,17 @@ - (dispatch_source_t)maintenanceTimer {
* Parse HTTP Date: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
*/
+ (NSDate *)dateFromHttpDateString:(NSString *)httpDate {
- static dispatch_once_t onceToken;
- static NSDateFormatter *_FC1123DateFormatter;
- static NSDateFormatter *_ANSICDateFormatter;
- static NSDateFormatter *_RFC850DateFormatter;
- dispatch_once(&onceToken, ^{
- _FC1123DateFormatter = CreateDateFormatter(@"EEE, dd MMM yyyy HH:mm:ss z");
- _ANSICDateFormatter = CreateDateFormatter(@"EEE MMM d HH:mm:ss yyyy");
- _RFC850DateFormatter = CreateDateFormatter(@"EEEE, dd-MMM-yy HH:mm:ss z");
- });
-
- __block NSDate *date = nil;
- dispatch_sync(get_date_formatter_queue(), ^{
- date = [_FC1123DateFormatter dateFromString:httpDate];
- if (!date) {
- // ANSI C date format - Sun Nov 6 08:49:37 1994
- date = [_ANSICDateFormatter dateFromString:httpDate];
- if (!date) {
- // RFC 850 date format - Sunday, 06-Nov-94 08:49:37 GMT
- date = [_RFC850DateFormatter dateFromString:httpDate];
- }
- }
- });
-
- return date;
+ char stringBuffer[256];
+ size_t stringLength = (size_t)CFStringGetLength((CFStringRef)httpDate);
+ const char *cStringPtr = (const char *)CFStringGetCStringPtr((CFStringRef)httpDate, kCFStringEncodingMacRoman);
+ if(cStringPtr == NULL) {
+ CFIndex usedBytes = 0L, convertedCount = 0L;
+ convertedCount = CFStringGetBytes((CFStringRef)httpDate, CFRangeMake(0L, (CFIndex)stringLength), kCFStringEncodingUTF8, '?', NO, (UInt8 *)stringBuffer, sizeof(stringBuffer) - 1L, &usedBytes);
+ if(((size_t)convertedCount != stringLength) || (usedBytes < 0L)) { return(NULL); }
+ stringBuffer[convertedCount] = 0;
+ cStringPtr = (const char *)stringBuffer;
+ }
+ return(_parseHTTPDate(cStringPtr, stringLength));
}
/*
@@ -565,4 +763,4 @@ - (void)dealloc {
@synthesize diskCachePath = _diskCachePath;
@synthesize diskCacheInfo = _diskCacheInfo;
-@end
+@end
View
36 SDURLCache.xcodeproj/project.pbxproj
@@ -276,31 +276,31 @@
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
- GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
- GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
- GCC_WARN_MISSING_PARENTHESES = YES;
- GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = NO;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
- GCC_WARN_STRICT_SELECTOR_MATCH = NO;
GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
- GCC_WARN_UNUSED_PARAMETER = NO;
+ GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
OTHER_LDFLAGS = "-ObjC";
- PREBINDING = NO;
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = iphoneos;
+ WARNING_CFLAGS = (
+ "-Wall",
+ "-Wextra",
+ );
};
name = Debug;
};
@@ -308,30 +308,30 @@
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
- GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
- GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
- GCC_WARN_MISSING_PARENTHESES = YES;
- GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = NO;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
- GCC_WARN_STRICT_SELECTOR_MATCH = NO;
GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
- GCC_WARN_UNUSED_PARAMETER = NO;
+ GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
OTHER_LDFLAGS = "-ObjC";
- PREBINDING = NO;
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = iphoneos;
+ WARNING_CFLAGS = (
+ "-Wall",
+ "-Wextra",
+ );
};
name = Release;
};
View
1  SDURLCacheTests.m
@@ -37,6 +37,7 @@ - (void)testHttpDateParser
- (void)testExpirationDateFromHeader
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+ [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
[dateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss z"];
NSDate *now = [NSDate date];
NSString *pastDate = [dateFormatter stringFromDate:[NSDate dateWithTimeInterval:-1000 sinceDate:now]];
Something went wrong with that request. Please try again.