@@ -182,6 +182,115 @@ size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
182
182
return nmemb ;
183
183
}
184
184
185
+ /*
186
+ * A folded header continuation line starts with any number of spaces or
187
+ * horizontal tab characters (SP or HTAB) as per RFC 7230 section 3.2.
188
+ * It is not a continuation line if the line starts with any other character.
189
+ */
190
+ static inline int is_hdr_continuation (const char * ptr , const size_t size )
191
+ {
192
+ return size && (* ptr == ' ' || * ptr == '\t' );
193
+ }
194
+
195
+ static size_t fwrite_wwwauth (char * ptr , size_t eltsize , size_t nmemb , void * p )
196
+ {
197
+ size_t size = eltsize * nmemb ;
198
+ struct strvec * values = & http_auth .wwwauth_headers ;
199
+ struct strbuf buf = STRBUF_INIT ;
200
+ const char * val ;
201
+ size_t val_len ;
202
+
203
+ /*
204
+ * Header lines may not come NULL-terminated from libcurl so we must
205
+ * limit all scans to the maximum length of the header line, or leverage
206
+ * strbufs for all operations.
207
+ *
208
+ * In addition, it is possible that header values can be split over
209
+ * multiple lines as per RFC 7230. 'Line folding' has been deprecated
210
+ * but older servers may still emit them. A continuation header field
211
+ * value is identified as starting with a space or horizontal tab.
212
+ *
213
+ * The formal definition of a header field as given in RFC 7230 is:
214
+ *
215
+ * header-field = field-name ":" OWS field-value OWS
216
+ *
217
+ * field-name = token
218
+ * field-value = *( field-content / obs-fold )
219
+ * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
220
+ * field-vchar = VCHAR / obs-text
221
+ *
222
+ * obs-fold = CRLF 1*( SP / HTAB )
223
+ * ; obsolete line folding
224
+ * ; see Section 3.2.4
225
+ */
226
+
227
+ /* Start of a new WWW-Authenticate header */
228
+ if (skip_iprefix_mem (ptr , size , "www-authenticate:" , & val , & val_len )) {
229
+ strbuf_add (& buf , val , val_len );
230
+
231
+ /*
232
+ * Strip the CRLF that should be present at the end of each
233
+ * field as well as any trailing or leading whitespace from the
234
+ * value.
235
+ */
236
+ strbuf_trim (& buf );
237
+
238
+ strvec_push (values , buf .buf );
239
+ http_auth .header_is_last_match = 1 ;
240
+ goto exit ;
241
+ }
242
+
243
+ /*
244
+ * This line could be a continuation of the previously matched header
245
+ * field. If this is the case then we should append this value to the
246
+ * end of the previously consumed value.
247
+ */
248
+ if (http_auth .header_is_last_match && is_hdr_continuation (ptr , size )) {
249
+ /*
250
+ * Trim the CRLF and any leading or trailing from this line.
251
+ */
252
+ strbuf_add (& buf , ptr , size );
253
+ strbuf_trim (& buf );
254
+
255
+ /*
256
+ * At this point we should always have at least one existing
257
+ * value, even if it is empty. Do not bother appending the new
258
+ * value if this continuation header is itself empty.
259
+ */
260
+ if (!values -> nr ) {
261
+ BUG ("should have at least one existing header value" );
262
+ } else if (buf .len ) {
263
+ char * prev = xstrdup (values -> v [values -> nr - 1 ]);
264
+
265
+ /* Join two non-empty values with a single space. */
266
+ const char * const sp = * prev ? " " : "" ;
267
+
268
+ strvec_pop (values );
269
+ strvec_pushf (values , "%s%s%s" , prev , sp , buf .buf );
270
+ free (prev );
271
+ }
272
+
273
+ goto exit ;
274
+ }
275
+
276
+ /* Not a continuation of a previously matched auth header line. */
277
+ http_auth .header_is_last_match = 0 ;
278
+
279
+ /*
280
+ * If this is a HTTP status line and not a header field, this signals
281
+ * a different HTTP response. libcurl writes all the output of all
282
+ * response headers of all responses, including redirects.
283
+ * We only care about the last HTTP request response's headers so clear
284
+ * the existing array.
285
+ */
286
+ if (skip_iprefix_mem (ptr , size , "http/" , & val , & val_len ))
287
+ strvec_clear (values );
288
+
289
+ exit :
290
+ strbuf_release (& buf );
291
+ return size ;
292
+ }
293
+
185
294
size_t fwrite_null (char * ptr , size_t eltsize , size_t nmemb , void * strbuf )
186
295
{
187
296
return nmemb ;
@@ -1896,6 +2005,8 @@ static int http_request(const char *url,
1896
2005
fwrite_buffer );
1897
2006
}
1898
2007
2008
+ curl_easy_setopt (slot -> curl , CURLOPT_HEADERFUNCTION , fwrite_wwwauth );
2009
+
1899
2010
accept_language = http_get_accept_language_header ();
1900
2011
1901
2012
if (accept_language )
0 commit comments