message.h 12.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*****************************************************************************
 * message.h: HTTP request/response
 *****************************************************************************
 * Copyright (C) 2015 Rémi Denis-Courmont
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Lesser General Public License for more details.
15 16 17 18 19 20 21 22
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include <stdint.h>

23 24 25 26 27 28 29 30
/**
 * \defgroup http_msg Messages
 * HTTP messages, header formatting and parsing
 * \ingroup http
 * @{
 * \file message.h
 */

31 32
struct vlc_http_msg;
struct block_t;
33
struct vlc_http_cookie_jar_t;
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

/**
 * Creates an HTTP request.
 *
 * Allocates an HTTP request message.
 *
 * @param method request method (e.g. "GET")
 * @param scheme protocol scheme (e.g. "https")
 * @param authority target host (e.g. "www.example.com:8080")
 * @param path request path (e.g. "/dir/page.html")
 * @return an HTTP stream or NULL on allocation failure
 */
struct vlc_http_msg *
vlc_http_req_create(const char *method, const char *scheme,
                    const char *authority, const char *path) VLC_USED;

/**
 * Creates an HTTP response.
 *
 * Allocates an HTTP response message.
 *
 * @param status HTTP status code
 * @return an HTTP stream or NULL on allocation failure
 */
struct vlc_http_msg *vlc_http_resp_create(unsigned status) VLC_USED;

/**
 * Destroys an HTTP message.
 */
63
void vlc_http_msg_destroy(struct vlc_http_msg *);
64 65

/**
66
 * Formats a header field.
67 68 69 70
 *
 * Adds an HTTP message header to an HTTP request or response.
 * All headers must be formatted before the message is sent.
 *
71 72
 * @param name header field name
 * @param fmt printf-style format string
73 74
 * @return 0 on success, -1 on error (out of memory)
 */
75
int vlc_http_msg_add_header(struct vlc_http_msg *, const char *name,
76 77 78
                            const char *fmt, ...) VLC_FORMAT(3,4);

/**
79
 * Sets the agent field.
80
 *
81
 * Sets the User-Agent or Server header field.
82
 */
83
int vlc_http_msg_add_agent(struct vlc_http_msg *, const char *);
84

85 86 87 88 89 90
/**
 * Gets the agent field.
 *
 * Gets the User-Agent or Server header field.
 */
const char *vlc_http_msg_get_agent(const struct vlc_http_msg *);
91

92
/**
93
 * Parses a timestamp header field.
94 95 96 97
 *
 * @param name header field name
 * @return a timestamp value, or -1 on error.
 */
98
time_t vlc_http_msg_get_time(const struct vlc_http_msg *, const char *name);
99 100

/**
101
 * Adds a timestamp header field.
102 103 104 105 106
 *
 * @param name header field name
 * @param t pointer to timestamp
 * @return 0 on success, -1 on error (errno is set accordingly)
 */
107
int vlc_http_msg_add_time(struct vlc_http_msg *, const char *name,
108 109
                          const time_t *t);

110
/**
111
 * Adds a Date header field.
112
 */
113
int vlc_http_msg_add_atime(struct vlc_http_msg *);
114 115 116 117 118 119 120 121

/**
 * Gets message date.
 *
 * Extracts the original date of the message from the HTTP Date header.
 *
 * @return a time value on success, -1 on error.
 */
122
time_t vlc_http_msg_get_atime(const struct vlc_http_msg *);
123 124 125 126 127 128 129 130 131

/**
 * Gets resource date.
 *
 * Extracts the last modification date of the message content from the HTTP
 * Last-Modified header.
 *
 * @return a time value on success, -1 on error.
 */
132
time_t vlc_http_msg_get_mtime(const struct vlc_http_msg *);
133 134 135 136

/**
 * Gets retry timeout.
 *
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
137
 * Extracts the time (in seconds) until the expiration of the "retry-after"
138 139 140 141 142
 * time-out in the HTTP message. If the header value is an absolute date, it
 * is converted relative to the current time.
 *
 * @return the time in seconds, zero if the date is overdue or on error.
 */
143
unsigned vlc_http_msg_get_retry_after(const struct vlc_http_msg *);
144

145
void vlc_http_msg_get_cookies(const struct vlc_http_msg *,
146
                              struct vlc_http_cookie_jar_t *,
147 148 149 150
                              const char *host, const char *path);
int vlc_http_msg_add_cookies(struct vlc_http_msg *,
                             struct vlc_http_cookie_jar_t *);

151 152
char *vlc_http_msg_get_basic_realm(const struct vlc_http_msg *);

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
/**
 * Adds Basic credentials.
 *
 * Formats a plain username and password pair using HTTP Basic (RFC7617)
 * syntax.
 *
 * @param proxy true for proxy authentication,
 *              false for origin server authentication
 * @param username null-terminated username
 * @param password null-terminated password
 * @return 0 on success, -1 on out-of-memory (ENOMEM) or if username or
 * password are invalid (EINVAL).
 */
int vlc_http_msg_add_creds_basic(struct vlc_http_msg *, bool proxy,
                                 const char *username, const char *password);


170
/**
171
 * Looks up an header field.
172
 *
173 174 175
 * Finds an HTTP header field by (case-insensitive) name inside an HTTP
 * message header. If the message has more than one matching field, their value
 * are folded (as permitted by protocol specifications).
176
 *
177 178
 * @return header field value (valid until message is destroyed),
 *         or NULL if no fields matched
179
 */
180
const char *vlc_http_msg_get_header(const struct vlc_http_msg *,
181 182
                                    const char *name);

183 184 185 186 187
/**
 * Gets response status code.
 *
 * @return status code (e.g. 404), or negative if request
 */
188
int vlc_http_msg_get_status(const struct vlc_http_msg *m);
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217

/**
 * Gets request method.
 *
 * @return request method (e.g. "GET"), or NULL if response
 */
const char *vlc_http_msg_get_method(const struct vlc_http_msg *);

/**
 * Gets request scheme.
 *
 * @return request scheme (e.g. "https"), or NULL if absent
 */
const char *vlc_http_msg_get_scheme(const struct vlc_http_msg *);

/**
 * Gets request authority.
 *
 * @return request authority (e.g. "www.example.com:8080"),
 *         or NULL if response
 */
const char *vlc_http_msg_get_authority(const struct vlc_http_msg *);

/**
 * Gets request absolute path.
 *
 * @return request absolute path (e.g. "/index.html"), or NULL if absent
 */
const char *vlc_http_msg_get_path(const struct vlc_http_msg *);
218

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
/**
 * Looks up a token in a header field.
 *
 * Finds the first occurence of a token within a HTTP field header.
 *
 * @param field HTTP header field name
 * @param token HTTP token name
 * @return the first byte of the token if found, NULL if not found.
 */
const char *vlc_http_msg_get_token(const struct vlc_http_msg *,
                                   const char *field, const char *token);

/**
 * Finds next token.
 *
234 235 236 237
 * Finds the following token in a HTTP header field value.
 *
 * @return First character of the following token,
 *         or NULL if there are no further tokens
238 239 240
 */
const char *vlc_http_next_token(const char *);

241 242 243
/**
 * Gets HTTP payload length.
 *
244 245 246
 * Determines the total length (in bytes) of the payload associated with the
 * HTTP message.
 *
247 248
 * @return byte length, or (uintmax_t)-1 if unknown.
 */
249
uintmax_t vlc_http_msg_get_size(const struct vlc_http_msg *);
250 251 252 253 254 255 256 257 258 259

/**
 * Gets next response headers.
 *
 * Discards the current response headers and gets the next set of response
 * headers for the same request. This is intended for HTTP 1xx continuation
 * responses and for message trailers.
 *
 * @param m current response headers (destroyed by the call)
 *
260
 * @return next response headers or NULL on error
261
 */
262
struct vlc_http_msg *vlc_http_msg_iterate(struct vlc_http_msg *) VLC_USED;
263 264 265 266 267 268 269 270 271 272 273

/**
 * Gets final response headers.
 *
 * Skips HTTP 1xx continue headers until a final set of response headers is
 * received. This is a convenience wrapper around vlc_http_msg_iterate() for
 * use when continuation headers are not useful (e.g. GET or CONNECT).
 *
 * @param m current response headers or NULL
 *
 * @return the final response headers (m if it was already final),
274
 *         NULL if the parameter was NULL, or NULL on error
275
 */
276
struct vlc_http_msg *vlc_http_msg_get_final(struct vlc_http_msg *) VLC_USED;
277 278 279 280 281 282 283 284

/**
 * Receives HTTP data.
 *
 * Dequeues the next block of data from an HTTP message. If no pending data has
 * been received, waits until data is received, the stream ends or the
 * underlying connection fails.
 *
285 286 287
 * @return data block
 * @retval NULL on end-of-stream
 * @retval vlc_http_error on fatal error
288
 */
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
struct block_t *vlc_http_msg_read(struct vlc_http_msg *) VLC_USED;

/** @} */

/**
 * \defgroup http_stream Streams
 * \ingroup http_connmgr
 *
 * HTTP request/response streams
 *
 * A stream is initiated by a client-side request header. It includes a
 * final response header, possibly preceded by one or more continuation
 * response headers. After the response header, a stream usually carries
 * a response payload.
 *
 * A stream may also carry a request payload (this is not supported so far).
 *
 * The HTTP stream constitutes the interface between an HTTP connection and
 * the higher-level HTTP messages layer.
 * @{
 */
310 311 312

struct vlc_http_stream;

313 314 315 316 317 318 319 320 321 322 323 324
/**
 * Error pointer value
 *
 * This is an error value for some HTTP functions that can return NULL in
 * non-error circumstances. Another return value is necessary to express
 * error/failure, which this is.
 * This compares different to NULL and to any valid pointer.
 *
 * @warning Dereferencing this pointer is undefined.
 */
extern void *const vlc_http_error;

325
void vlc_http_msg_attach(struct vlc_http_msg *m, struct vlc_http_stream *s);
326 327
struct vlc_http_msg *vlc_http_msg_get_initial(struct vlc_http_stream *s)
VLC_USED;
328

329 330 331 332
/** HTTP stream callbacks
 *
 * Connection-specific callbacks for stream manipulation
 */
333 334 335 336
struct vlc_http_stream_cbs
{
    struct vlc_http_msg *(*read_headers)(struct vlc_http_stream *);
    struct block_t *(*read)(struct vlc_http_stream *);
337
    void (*close)(struct vlc_http_stream *, bool abort);
338 339
};

340
/** HTTP stream */
341 342 343 344 345
struct vlc_http_stream
{
    const struct vlc_http_stream_cbs *cbs;
};

346 347 348 349 350 351 352 353 354 355 356
/**
 * Reads one message header.
 *
 * Reads the next message header of an HTTP stream from the network.
 * There is always exactly one request header per stream. There is usually
 * one response header per stream, except for continuation (1xx) headers.
 *
 * @warning The caller is responsible for reading headers at appropriate
 * times as intended by the protocol. Failure to do so may result in protocol
 * dead lock, and/or (HTTP 1.x) connection failure.
 */
357 358 359 360 361 362
static inline
struct vlc_http_msg *vlc_http_stream_read_headers(struct vlc_http_stream *s)
{
    return s->cbs->read_headers(s);
}

363 364 365 366
/**
 * Reads message payload data.
 *
 * Reads the next block of data from the message payload of an HTTP stream.
367 368 369 370
 *
 * @return a block of data (use block_Release() to free it)
 * @retval NULL The end of the stream was reached.
 * @retval vlc_http_error The stream encountered a fatal error.
371
 */
372 373 374 375 376
static inline struct block_t *vlc_http_stream_read(struct vlc_http_stream *s)
{
    return s->cbs->read(s);
}

377 378 379 380 381 382
/**
 * Closes an HTTP stream.
 *
 * Releases all resources associated or held by an HTTP stream. Any unread
 * header or data is discarded.
 */
383
static inline void vlc_http_stream_close(struct vlc_http_stream *s, bool abort)
384
{
385
    s->cbs->close(s, abort);
386 387
}

388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
/** @} */

/**
 * Formats an HTTP 1.1 message header.
 *
 * Formats an message header in HTTP 1.x format, using HTTP version 1.1.
 *
 * @param m message to format/serialize
 * @param lenp location to write the length of the formatted message in bytes
 *             [OUT]
 * @param proxied whether the message is meant for sending to a proxy rather
 *                than an origin (only relevant for requests)
 * @return A heap-allocated nul-terminated string or *lenp bytes,
 *         or NULL on error
 */
403 404
char *vlc_http_msg_format(const struct vlc_http_msg *m, size_t *restrict lenp,
                          bool proxied) VLC_USED;
405 406 407 408

/**
 * Parses an HTTP 1.1 message header.
 */
409 410 411 412
struct vlc_http_msg *vlc_http_msg_headers(const char *msg) VLC_USED;

struct vlc_h2_frame;

413 414 415
/**
 * Formats an HTTP 2.0 HEADER frame.
 */
416 417
struct vlc_h2_frame *vlc_http_msg_h2_frame(const struct vlc_http_msg *m,
                                           uint_fast32_t stream_id, bool eos);
418 419 420 421

/**
 * Parses an HTTP 2.0 header table.
 */
422 423
struct vlc_http_msg *vlc_http_msg_h2_headers(unsigned count,
                                             const char *const headers[][2]);