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