@@ -62,14 +62,7 @@ var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/;
62
62
// date-time parsing constants (RFC6265 S5.1.1)
63
63
64
64
var DATE_DELIM = / [ \x09 \x20 - \x2F \x3B - \x40 \x5B - \x60 \x7B - \x7E ] / ;
65
- var DAY_OF_MONTH = / ^ ( \d { 1 , 2 } ) (?: [ ^ \d ] | $ ) / ;
66
65
67
- // S5.1.1 for "hms-time" -- is one or two digits each separated by :
68
- // Cannot have non-digits beside the numbers like in other parts of the
69
- // construction.
70
- var TIME = / ^ ( \d { 1 , 2 } ) : ( \d { 1 , 2 } ) : ( \d { 1 , 2 } ) (?: [ ^ \d ] | $ ) / ; // only anchor at start
71
-
72
- var MONTH = / ^ ( J a n | F e b | M a r | A p r | M a y | J u n | J u l | A u g | S e p | O c t | N o v | D e c ) / i;
73
66
var MONTH_TO_NUM = {
74
67
jan :0 , feb :1 , mar :2 , apr :3 , may :4 , jun :5 ,
75
68
jul :6 , aug :7 , sep :8 , oct :9 , nov :10 , dec :11
@@ -81,13 +74,80 @@ var NUM_TO_DAY = [
81
74
'Sun' , 'Mon' , 'Tue' , 'Wed' , 'Thu' , 'Fri' , 'Sat'
82
75
] ;
83
76
84
- var YEAR = / ^ ( \d { 2 } | \d { 4 } ) (?: [ ^ \d ] | $ ) / ; // 2 or 4 digits, anchored at start
85
-
86
77
var MAX_TIME = 2147483647000 ; // 31-bit max
87
78
var MIN_TIME = 0 ; // 31-bit min
88
79
80
+ /*
81
+ * Parses a Natural number (i.e., non-negative integer) with either the
82
+ * <min>*<max>DIGIT ( non-digit *OCTET )
83
+ * or
84
+ * <min>*<max>DIGIT
85
+ * grammar (RFC6265 S5.1.1).
86
+ *
87
+ * The "trailingOK" boolean controls if the grammar accepts a
88
+ * "( non-digit *OCTET )" trailer.
89
+ */
90
+ function parseDigits ( token , minDigits , maxDigits , trailingOK ) {
91
+ var count = 0 ;
92
+ while ( count < token . length ) {
93
+ var c = token . charCodeAt ( count ) ;
94
+ // "non-digit = %x00-2F / %x3A-FF"
95
+ if ( c <= 0x2F || c >= 0x3A ) {
96
+ break ;
97
+ }
98
+ count ++ ;
99
+ }
100
+
101
+ // constrain to a minimum and maximum number of digits.
102
+ if ( count < minDigits || count > maxDigits ) {
103
+ return null ;
104
+ }
89
105
90
- // RFC6265 S5.1.1 date parser:
106
+ if ( ! trailingOK && count != token . length ) {
107
+ return null ;
108
+ }
109
+
110
+ return parseInt ( token . substr ( 0 , count ) , 10 ) ;
111
+ }
112
+
113
+ function parseTime ( token ) {
114
+ var parts = token . split ( ':' ) ;
115
+ var result = [ 0 , 0 , 0 ] ;
116
+
117
+ /* RF6256 S5.1.1:
118
+ * time = hms-time ( non-digit *OCTET )
119
+ * hms-time = time-field ":" time-field ":" time-field
120
+ * time-field = 1*2DIGIT
121
+ */
122
+
123
+ if ( parts . length !== 3 ) {
124
+ return null ;
125
+ }
126
+
127
+ for ( var i = 0 ; i < 3 ; i ++ ) {
128
+ // "time-field" must be strictly "1*2DIGIT", HOWEVER, "hms-time" can be
129
+ // followed by "( non-digit *OCTET )" so therefore the last time-field can
130
+ // have a trailer
131
+ var trailingOK = ( i == 2 ) ;
132
+ var num = parseDigits ( parts [ i ] , 1 , 2 , trailingOK ) ;
133
+ if ( num === null ) {
134
+ return null ;
135
+ }
136
+ result [ i ] = num ;
137
+ }
138
+
139
+ return result ;
140
+ }
141
+
142
+ function parseMonth ( token ) {
143
+ token = String ( token ) . substr ( 0 , 3 ) . toLowerCase ( ) ;
144
+ var num = MONTH_TO_NUM [ token ] ;
145
+ return num >= 0 ? num : null ;
146
+ }
147
+
148
+ /*
149
+ * RFC6265 S5.1.1 date parser (see RFC for full grammar)
150
+ */
91
151
function parseDate ( str ) {
92
152
if ( ! str ) {
93
153
return ;
@@ -103,9 +163,9 @@ function parseDate(str) {
103
163
}
104
164
105
165
var hour = null ;
106
- var minutes = null ;
107
- var seconds = null ;
108
- var day = null ;
166
+ var minute = null ;
167
+ var second = null ;
168
+ var dayOfMonth = null ;
109
169
var month = null ;
110
170
var year = null ;
111
171
@@ -123,22 +183,12 @@ function parseDate(str) {
123
183
* the date-token, respectively. Skip the remaining sub-steps and continue
124
184
* to the next date-token.
125
185
*/
126
- if ( seconds === null ) {
127
- result = TIME . exec ( token ) ;
186
+ if ( second === null ) {
187
+ result = parseTime ( token ) ;
128
188
if ( result ) {
129
- hour = parseInt ( result [ 1 ] , 10 ) ;
130
- minutes = parseInt ( result [ 2 ] , 10 ) ;
131
- seconds = parseInt ( result [ 3 ] , 10 ) ;
132
- /* RFC6265 S5.1.1.5:
133
- * [fail if]
134
- * * the hour-value is greater than 23,
135
- * * the minute-value is greater than 59, or
136
- * * the second-value is greater than 59.
137
- */
138
- if ( hour > 23 || minutes > 59 || seconds > 59 ) {
139
- return ;
140
- }
141
-
189
+ hour = result [ 0 ] ;
190
+ minute = result [ 1 ] ;
191
+ second = result [ 2 ] ;
142
192
continue ;
143
193
}
144
194
}
@@ -148,16 +198,11 @@ function parseDate(str) {
148
198
* the day-of-month-value to the number denoted by the date-token. Skip
149
199
* the remaining sub-steps and continue to the next date-token.
150
200
*/
151
- if ( day === null ) {
152
- result = DAY_OF_MONTH . exec ( token ) ;
153
- if ( result ) {
154
- day = parseInt ( result [ 1 ] , 10 ) ;
155
- /* RFC6265 S5.1.1.5:
156
- * [fail if] the day-of-month-value is less than 1 or greater than 31
157
- */
158
- if ( day < 1 || day > 31 ) {
159
- return ;
160
- }
201
+ if ( dayOfMonth === null ) {
202
+ // "day-of-month = 1*2DIGIT ( non-digit *OCTET )"
203
+ result = parseDigits ( token , 1 , 2 , true ) ;
204
+ if ( result !== null ) {
205
+ dayOfMonth = result ;
161
206
continue ;
162
207
}
163
208
}
@@ -168,47 +213,63 @@ function parseDate(str) {
168
213
* continue to the next date-token.
169
214
*/
170
215
if ( month === null ) {
171
- result = MONTH . exec ( token ) ;
172
- if ( result ) {
173
- month = MONTH_TO_NUM [ result [ 1 ] . toLowerCase ( ) ] ;
216
+ result = parseMonth ( token ) ;
217
+ if ( result !== null ) {
218
+ month = result ;
174
219
continue ;
175
220
}
176
221
}
177
222
178
- /* 2.4. If the found-year flag is not set and the date-token matches the year
179
- * production, set the found-year flag and set the year-value to the number
180
- * denoted by the date-token. Skip the remaining sub-steps and continue to
181
- * the next date-token.
223
+ /* 2.4. If the found-year flag is not set and the date-token matches the
224
+ * year production, set the found-year flag and set the year-value to the
225
+ * number denoted by the date-token. Skip the remaining sub-steps and
226
+ * continue to the next date-token.
182
227
*/
183
228
if ( year === null ) {
184
- result = YEAR . exec ( token ) ;
185
- if ( result ) {
186
- year = parseInt ( result [ 0 ] , 10 ) ;
229
+ // "year = 2*4DIGIT ( non-digit *OCTET )"
230
+ result = parseDigits ( token , 2 , 4 , true ) ;
231
+ if ( result !== null ) {
232
+ year = result ;
187
233
/* From S5.1.1:
188
234
* 3. If the year-value is greater than or equal to 70 and less
189
235
* than or equal to 99, increment the year-value by 1900.
190
236
* 4. If the year-value is greater than or equal to 0 and less
191
237
* than or equal to 69, increment the year-value by 2000.
192
238
*/
193
- if ( 70 <= year && year <= 99 ) {
239
+ if ( year >= 70 && year <= 99 ) {
194
240
year += 1900 ;
195
- } else if ( 0 <= year && year <= 69 ) {
241
+ } else if ( year >= 0 && year <= 69 ) {
196
242
year += 2000 ;
197
243
}
198
-
199
- if ( year < 1601 ) {
200
- return ; // 5. ... the year-value is less than 1601
201
- }
202
244
}
203
245
}
204
246
}
205
247
206
- if ( seconds === null || day === null || month === null || year === null ) {
207
- return ; // 5. ... at least one of the found-day-of-month, found-month, found-
208
- // year, or found-time flags is not set,
248
+ /* RFC 6265 S5.1.1
249
+ * "5. Abort these steps and fail to parse the cookie-date if:
250
+ * * at least one of the found-day-of-month, found-month, found-
251
+ * year, or found-time flags is not set,
252
+ * * the day-of-month-value is less than 1 or greater than 31,
253
+ * * the year-value is less than 1601,
254
+ * * the hour-value is greater than 23,
255
+ * * the minute-value is greater than 59, or
256
+ * * the second-value is greater than 59.
257
+ * (Note that leap seconds cannot be represented in this syntax.)"
258
+ *
259
+ * So, in order as above:
260
+ */
261
+ if (
262
+ dayOfMonth === null || month === null || year === null || second === null ||
263
+ dayOfMonth < 1 || dayOfMonth > 31 ||
264
+ year < 1601 ||
265
+ hour > 23 ||
266
+ minute > 59 ||
267
+ second > 59
268
+ ) {
269
+ return ;
209
270
}
210
271
211
- return new Date ( Date . UTC ( year , month , day , hour , minutes , seconds ) ) ;
272
+ return new Date ( Date . UTC ( year , month , dayOfMonth , hour , minute , second ) ) ;
212
273
}
213
274
214
275
function formatDate ( date ) {
0 commit comments