Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  message.c   Sprache: C

 

/*****************************************************************************
 * message.c: 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
 * GNU Lesser General Public License for more details.
 *
 * 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.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <assert.h>
#include <errno.h>
#include <stdalign.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <vlc_common.h>
#include <vlc_http.h>
#include <vlc_block.h>
#include <vlc_strings.h>
#include <vlc_memstream.h>
#include "message.h"
#include "h2frame.h"

struct vlc_http_msg
{
    short status;
    char *method;
    char *scheme;
    char *authority;
    char *path;
    char *(*headers)[2];
    unsigned count;
    struct vlc_http_stream *payload;
};

/* Maximum alignment for safe conversion to/from any specific pointer type */
static const char alignas (max_align_t) vlc_http_error_loc;

void *const vlc_http_error = (char *)&vlc_http_error_loc;

static bool vlc_http_is_token(const char *);

static ssize_t vlc_http_msg_find_header(const struct vlc_http_msg *m,
                                        const char *name)
{
    for (unsigned i = 0; i < m->count; i++)
        if (!strcasecmp(m->headers[i][0], name))
            return i;
    return -1;
}

static int vlc_http_msg_vadd_header(struct vlc_http_msg *m, const char *name,
                                    const char *fmt, va_list ap)
{
    if (!vlc_http_is_token(name))
    {   /* Not a valid field name, i.e. not an HTTP token */
        errno = EINVAL;
        return -1;
    }

    char *value;
    int len = vasprintf(&value, fmt, ap);
    if (unlikely(len < 0))
        return -1;

    /* IETF RFC7230 §3.2.4 */
    for (char *p = value; *p; p++)
        if (*p == '\r' || *p == '\n')
            *p = ' ';

    /* Discard leading OWS */
    size_t crop = strspn(value, "\t ");
    if (crop > 0)
    {
        assert((unsigned)len >= crop);
        memmove(value, value + crop, len - crop + 1);
        len -= crop;
    }

    /* Discard trailing OWS */
    while (len > 0 && (value[len - 1] == '\t' || value[len - 1] == ' '))
        value[--len] = '\0';

    /* Fold identically named header field values. This is unfortunately not
     * possible for Set-Cookie, while Cookie requires a special separator. */

    ssize_t idx = vlc_http_msg_find_header(m, name);
    if (idx >= 0 && strcasecmp(name, "Set-Cookie"))
    {
        char *merged;
        char sep = strcasecmp(name, "Cookie") ? ',' : ';';

        int val = asprintf(&merged, "%s%c %s", m->headers[idx][1], sep, value);

        free(value);

        if (unlikely(val == -1))
            return -1;

        free(m->headers[idx][1]);
        m->headers[idx][1] = merged;
        return 0;
    }

    char *(*h)[2] = realloc(m->headers, sizeof (char *[2]) * (m->count + 1));
    if (unlikely(h == NULL))
    {
        free(value);
        return -1;
    }

    m->headers = h;
    h += m->count;

    h[0][0] = strdup(name);
    if (unlikely(h[0][0] == NULL))
    {
        free(value);
        return -1;
    }

    h[0][1] = value;
    m->count++;
    return 0;
}

int vlc_http_msg_add_header(struct vlc_http_msg *m, const char *name,
                            const char *fmt, ...)
{
    va_list ap;
    int ret;

    va_start(ap, fmt);
    ret = vlc_http_msg_vadd_header(m, name, fmt, ap);
    va_end(ap);
    return ret;
}

const char *vlc_http_msg_get_header(const struct vlc_http_msg *m,
                                    const char *name)
{
    ssize_t idx = vlc_http_msg_find_header(m, name);
    if (idx < 0)
    {
        errno = ENOENT;
        return NULL;
    }
    return m->headers[idx][1];
}

int vlc_http_msg_get_status(const struct vlc_http_msg *m)
{
    return m->status;
}

const char *vlc_http_msg_get_method(const struct vlc_http_msg *m)
{
    return m->method;
}

const char *vlc_http_msg_get_scheme(const struct vlc_http_msg *m)
{
    return m->scheme;
}

const char *vlc_http_msg_get_authority(const struct vlc_http_msg *m)
{
    return m->authority;
}

const char *vlc_http_msg_get_path(const struct vlc_http_msg *m)
{
    return m->path;
}

void vlc_http_msg_destroy(struct vlc_http_msg *m)
{
    if (m->payload != NULL)
        vlc_http_stream_close(m->payload, false);

    for (unsigned i = 0; i < m->count; i++)
    {
        free(m->headers[i][0]);
        free(m->headers[i][1]);
    }

    free(m->headers);
    free(m->path);
    free(m->authority);
    free(m->scheme);
    free(m->method);
    free(m);
}

struct vlc_http_msg *
vlc_http_req_create(const char *method, const char *scheme,
                    const char *authority, const char *path)
{
    struct vlc_http_msg *m = malloc(sizeof (*m));
    if (unlikely(m == NULL))
        return NULL;

    assert(method != NULL);
    m->status = -1;
    m->method = strdup(method);
    m->scheme = (scheme != NULL) ? strdup(scheme) : NULL;
    m->authority = (authority != NULL) ? strdup(authority) : NULL;
    m->path = (path != NULL) ? strdup(path) : NULL;
    m->count = 0;
    m->headers = NULL;
    m->payload = NULL;

    if (unlikely(m->method == NULL
              || (scheme != NULL && m->scheme == NULL)
              || (authority != NULL && m->authority == NULL)
              || (path != NULL && m->path == NULL)))
    {
        vlc_http_msg_destroy(m);
        m = NULL;
    }
    return m;
}

struct vlc_http_msg *vlc_http_resp_create(unsigned status)
{
    struct vlc_http_msg *m = malloc(sizeof (*m));
    if (unlikely(m == NULL))
        return NULL;

    assert(status < 1000);
    m->status = status;
    m->method = NULL;
    m->scheme = NULL;
    m->authority = NULL;
    m->path = NULL;
    m->count = 0;
    m->headers = NULL;
    m->payload = NULL;
    return m;
}

void vlc_http_msg_attach(struct vlc_http_msg *m, struct vlc_http_stream *s)
{
    assert(m->payload == NULL);
    m->payload = s;
}

struct vlc_http_msg *vlc_http_msg_iterate(struct vlc_http_msg *m)
{
    struct vlc_http_msg *next = vlc_http_stream_read_headers(m->payload);

    if (next != NULL)
        m->payload = NULL;

    vlc_http_msg_destroy(m);
    return next;
}

struct vlc_http_msg *vlc_http_msg_get_initial(struct vlc_http_stream *s)
{
    struct vlc_http_msg *m = vlc_http_stream_read_headers(s);
    if (m == NULL)
        vlc_http_stream_close(s, false);
    return m;
}

struct vlc_http_msg *vlc_http_msg_get_final(struct vlc_http_msg *m)
{
    while (m != NULL && (vlc_http_msg_get_status(m) / 100) == 1)
        m = vlc_http_msg_iterate(m);
    return m;
}

block_t *vlc_http_msg_read(struct vlc_http_msg *m)
{
    if (m->payload == NULL)
        return NULL;

    return vlc_http_stream_read(m->payload);
}

int vlc_http_msg_write(struct vlc_http_msg *m, block_t *block, bool eos)
{
    if (m->payload == NULL)
        return -1;

    /* Ideally, we'd send the end-of-stream with the last block of data.
     * But if there are zero blocks, then we have to send it separately.
     */

    if (block == NULL && eos)
        return vlc_http_stream_write(m->payload, NULL, 0, true);

    while (block != NULL)
    {
        block_t *next = block->p_next;
        bool end = eos && next == NULL;

        if (vlc_http_stream_write(m->payload, block->p_buffer, block->i_buffer,
                                  end) < (ssize_t)block->i_buffer)
            goto error;

        block_Release(block);
        block = next;
    }

    return 0;
error:
    block_ChainRelease(block);
    return -1;
}

/* Serialization and deserialization */

char *vlc_http_msg_format(const struct vlc_http_msg *m, size_t *restrict lenp,
                          bool proxied, bool chunked)
{
    struct vlc_memstream stream;

    vlc_memstream_open(&stream);

    if (m->status < 0)
    {
        vlc_memstream_printf(&stream, "%s ", m->method);
        if (proxied)
            vlc_memstream_printf(&stream, "%s://%s", m->scheme, m->authority);
        vlc_memstream_printf(&stream, "%s HTTP/1.1\r\nHost: %s\r\n",
                             m->path ? m->path : m->authority, m->authority);
    }
    else
        vlc_memstream_printf(&stream, "HTTP/1.1 %03hd .\r\n", m->status);

    for (unsigned i = 0; i < m->count; i++)
        vlc_memstream_printf(&stream, "%s: %s\r\n",
                             m->headers[i][0], m->headers[i][1]);

    if (chunked)
        vlc_memstream_puts(&stream, "Transfer-Encoding: chunked\r\n");

    vlc_memstream_puts(&stream, "\r\n");

    if (vlc_memstream_close(&stream))
        return NULL;

    if (lenp != NULL)
        *lenp = stream.length;
    return stream.ptr;
}

struct vlc_http_msg *vlc_http_msg_headers(const char *msg)
{
    struct vlc_http_msg *m;
    unsigned short code;

    if (sscanf(msg, "HTTP/1.%*1u %3hu %*s", &code) == 1)
    {
        m = vlc_http_resp_create(code);
        if (unlikely(m == NULL))
            return NULL;
    }
    else
        return NULL; /* TODO: request support */

    msg = strstr(msg, "\r\n");
    if (msg == NULL)
        goto error;

    while (strcmp(msg + 2, "\r\n"))
    {
        const char *eol = msg;

        do
        {
            eol = strstr(eol + 2, "\r\n");
            if (eol == NULL)
                goto error;
        }   /* Deal with legacy obs-fold (i.e. multi-line header) */
        while (eol[2] == ' ' || eol[2] == '\t');

        msg += 2; /* skip CRLF */

        const char *colon = memchr(msg, ':', eol - msg);
        if (colon == NULL || colon == msg)
            goto error;

        char *name = strndup(msg, colon - msg);
        if (unlikely(name == NULL))
            goto error;

        colon++;
        colon += strspn(colon, " \t");

        if (unlikely(vlc_http_msg_add_header(m, name, "%.*s",
                                             (int)(eol - colon), colon)))
        {
            free(name);
            goto error;
        }
        free(name);
        msg = eol;
    }

    return m;
error:
    vlc_http_msg_destroy(m);
    return NULL;
}

struct vlc_h2_frame *vlc_http_msg_h2_frame(const struct vlc_http_msg *m,
                                           uint_fast32_t stream_id, bool eos)
{
    for (unsigned j = 0; j < m->count; j++)
    {   /* No HTTP 1 specific headers */
        assert(strcasecmp(m->headers[j][0], "Connection"));
        assert(strcasecmp(m->headers[j][0], "Upgrade"));
        assert(strcasecmp(m->headers[j][0], "HTTP2-Settings"));
    }

    const char *(*headers)[2] = vlc_alloc(m->count + 5, sizeof (char *[2]));
    if (unlikely(headers == NULL))
        return NULL;

    struct vlc_h2_frame *f;
    unsigned i = 0;
    char status[4];

    if (m->status >= 0)
    {
        if (m->status >= 1000) vlc_assert_unreachable();
        snprintf(status, ARRAY_SIZE(status), "%hd", m->status);
        headers[i][0] = ":status";
        headers[i][1] = status;
        i++;
    }
    if (m->method != NULL)
    {
        headers[i][0] = ":method";
        headers[i][1] = m->method;
        i++;
    }
    if (m->scheme != NULL)
    {
        headers[i][0] = ":scheme";
        headers[i][1] = m->scheme;
        i++;
    }
    if (m->authority != NULL)
    {
        headers[i][0] = ":authority";
        headers[i][1] = m->authority;
        i++;
    }
    if (m->path != NULL)
    {
        headers[i][0] = ":path";
        headers[i][1] = m->path;
        i++;
    }
    if (m->count > 0)
    {
        memcpy(headers + i, m->headers, m->count * sizeof (*headers));
        i += m->count;
    }

    f = vlc_h2_frame_headers(stream_id, VLC_H2_DEFAULT_MAX_FRAME, eos,
                             i, headers);
    free(headers);
    return f;
}

struct vlc_http_msg *vlc_http_msg_h2_headers(unsigned n,
                                             const char *const hdrs[][2])
{
    struct vlc_http_msg *m = vlc_http_resp_create(0);
    if (unlikely(m == NULL))
        return NULL;

    for (unsigned i = 0; i < n; i++)
    {
        const char *name = hdrs[i][0];
        const char *value = hdrs[i][1];

        /* NOTE: HPACK always returns lower-case names, so strcmp() is fine. */
        if (!strcmp(name, ":status"))
        {
            char *end;
            unsigned long status = strtoul(value, &end, 10);

            if (m->status != 0 || status > 999 || *end != '\0')
                goto error; /* Not a three decimal digits status! */

            m->status = status;
            continue;
        }

        if (!strcmp(name, ":method"))
        {
            if (m->method != NULL)
                goto error;

            m->method = strdup(value);
            if (unlikely(m->method == NULL))
                goto error;

            m->status = -1; /* this is a request */
            continue;
        }

        if (!strcmp(name, ":scheme"))
        {
            if (m->scheme != NULL)
                goto error;

            m->scheme = strdup(value);
            if (unlikely(m->scheme == NULL))
                goto error;
            continue;
        }

        if (!strcmp(name, ":authority"))
        {
            if (m->authority != NULL)
                goto error;

            m->authority = strdup(value);
            if (unlikely(m->authority == NULL))
                goto error;
            continue;
        }

        if (!strcmp(name, ":path"))
        {
            if (m->path != NULL)
                goto error;

            m->path = strdup(value);
            if (unlikely(m->path == NULL))
                goto error;
            continue;
        }

        if (vlc_http_msg_add_header(m, name, "%s", value))
            goto error;
    }

    if ((m->status < 0) == (m->method == NULL))
    {   /* Must be either a request or response. Not both, not neither. */
error:
        vlc_http_msg_destroy(m);
        m = NULL;
    }
    return m;
}

/* Header helpers */

char *vlc_http_authority(const char *host, unsigned port)
{
    static const char *const formats[4] = { "%s", "[%s]", "%s:%u", "[%s]:%u" };
    const bool brackets = strchr(host, ':') != NULL;
    const char *fmt = formats[brackets + 2 * (port != 0)];
    char *authority;

    if (unlikely(asprintf(&authority, fmt, host, port) == -1))
        return NULL;
    return authority;
}

static int vlc_http_istoken(int c)
{   /* IETF RFC7230 §3.2.6 */
    return (c >= '0' && c <= '9')
        || (c >= 'a' && c <= 'z')
        || (c >= 'A' && c <= 'Z')
        || (c && strchr("!#$%&'*+-.^_`|~", c) != NULL);
}

static int vlc_http_isctext(int c)
{   /* IETF RFC7230 §3.2.6 */
    return (c == '\t') || (c == ' ') || (c >= 0x21 && c <= 0x27)
        || (c >= 0x2A && c <= 0x5B) || (c >= 0x5D && c <= 0x7E)
        || (c >= 0x80);
}

static size_t vlc_http_token_length(const char *str)
{
    size_t i = 0;

    while (vlc_http_istoken(str[i]))
        i++;
    return i;
}

static size_t vlc_http_quoted_length(const char *str)
{
    size_t i = 0;
    unsigned char c;

    if (str[i++] != '"')
        return 0;

    do
    {
        c = str[i++];

        if (c == '\0')
            return 0;

        if (c == '\\') /* Quoted pair */
        {
            unsigned char q = str[i++];
            if (q < 32 && q != '\t')
                return 0;
        }
    }
    while (c != '"');

    return i;
}

static bool vlc_http_is_token(const char *str)
{
    size_t len = vlc_http_token_length(str);
    return len > 0 && str[len] == '\0';
}

const char *vlc_http_next_token(const char *value)
{   /* We handle either token or token = token / quoted-string */
    value += strcspn(value, ",\"");
    if (!*value)
        return NULL;

    value += vlc_http_quoted_length(value);
    return value + strspn(value, "\t ,");
}

static const char *vlc_http_get_token(const char *value, const char *token)
{
    const size_t length = strlen(token);

    while (value != NULL)
    {
        if (vlc_http_token_length(value) == length
         && !strncasecmp(token, value, length))
            return value;

        value = vlc_http_next_token(value);
    }

    return NULL;
}

static char *vlc_http_get_token_value(const char *value, const char *token)
{
    value = vlc_http_get_token(value, token);
    if (value == NULL)
        return NULL;

    value += vlc_http_token_length(value);
    value += strspn(value, " \t"); /* BWS */

    if (*value != '=')
        return NULL;

    value++;
    value += strspn(value, " \t"); /* BWS */

    size_t len = vlc_http_quoted_length(value);
    if (len == 0)
        return NULL;

    assert(len >= 2);
    value++;
    len -= 2;

    char *out = malloc(len + 1), *p;
    if (unlikely(out == NULL))
        return NULL;

    for (p = out; len > 0; len--)
    {
        char c = *(value++);
        if (c == '\\') /* Quoted pair */
        {
            c = *(value++);
            len--;
        }
        *(p++) = c;
    }
    *p = '\0';
    return out;
}

const char *vlc_http_msg_get_token(const struct vlc_http_msg *msg,
                                   const char *field, const char *token)
{
    return vlc_http_get_token(vlc_http_msg_get_header(msg, field), token);
}

static size_t vlc_http_comment_length(const char *str)
{   /* IETF RFC7230 §3.2.6 */
    if (*str != '(')
        return 0;

    size_t i = 1;

    for (size_t nested = 1; nested > 0; i++)
    {
        unsigned char c = str[i];

        if (c == ')')
            nested--;
        else
        if (c == '(') /* Nested comment */
            nested++;
        else
        if (c == '\\') /* Quoted pair */
        {
            i++;
            if (str[i] < 32)
                return 0;
        }
        else
        if (!vlc_http_isctext(c))
            return 0;
    }
    return i;
}

static bool vlc_http_is_agent(const char *s)
{   /* IETF RFC7231 §5.5.3 and §7.4.2 */
    if (!vlc_http_istoken(*s))
        return false;

    for (;;)
    {
        size_t l = vlc_http_token_length(s);
        if (l != 0) /* product */
        {
            if (s[l] == '/') /* product version */
            {
                s += l + 1;
                l = vlc_http_token_length(s);
            }
        }
        else
            l = vlc_http_comment_length(s);

        if (l == 0)
            break;

        s += l;

        if (*s == '\0')
            return true;

        l = strspn(s, "\t "); /* RWS */

        if (l == 0)
            break;

        s += l;
    }

    return false;
}

int vlc_http_msg_add_agent(struct vlc_http_msg *m, const char *str)
{
    const char *hname = (m->status < 0) ? "User-Agent" : "Server";

    if (!vlc_http_is_agent(str))
    {
        errno = EINVAL;
        return -1;
    }
    return vlc_http_msg_add_header(m, hname, "%s", str);
}

const char *vlc_http_msg_get_agent(const struct vlc_http_msg *m)
{
    const char *hname = (m->status < 0) ? "User-Agent" : "Server";
    const char *str = vlc_http_msg_get_header(m, hname);

    return (str != NULL && vlc_http_is_agent(str)) ? str : NULL;
}

static const char vlc_http_days[7][4] = {
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char vlc_http_months[12][4] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

int vlc_http_msg_add_time(struct vlc_http_msg *m, const char *hname,
                          const time_t *t)
{
    struct tm tm;

    if (gmtime_r(t, &tm) == NULL)
        return -1;
    return vlc_http_msg_add_header(m, hname,
                                   "%s, %02d %s %04d %02d:%02d:%02d GMT",
                                   vlc_http_days[tm.tm_wday], tm.tm_mday,
                                   vlc_http_months[tm.tm_mon],
                                   1900 + tm.tm_year,
                                   tm.tm_hour, tm.tm_min, tm.tm_sec);
}

int vlc_http_msg_add_atime(struct vlc_http_msg *m)
{
    time_t now;

    time(&now);
    return vlc_http_msg_add_time(m, "Date", &now);
}

time_t vlc_http_mktime(const char *str)
{   /* IETF RFC7231 §7.1.1.1 */
    struct tm tm;
    char mon[4];

    /* Internet Message Format date */
    if (sscanf(str, "%*c%*c%*c, %2d %3s %4d %2d:%2d:%2d", &tm.tm_mday, mon,
               &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6
    /* ANSI C format */
     || sscanf(str, "%*3s %3s %2d %2d:%2d:%2d %4d", mon, &tm.tm_mday,
               &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &tm.tm_year) == 6)
        tm.tm_year -= 1900;
    /* RFC850 date */
    else if (sscanf(str, "%*[^,], %2d-%3s-%2d %2d:%2d:%2d", &tm.tm_mday, mon,
                    &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6)
    {
        if (tm.tm_year <= 75)
            tm.tm_year += 100; /* Y2K compat, sort of */
    }
    else /* Unknown format */
        goto error;

    for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++)
        if (!strcmp(mon, vlc_http_months[tm.tm_mon])) /* found month */
            return timegm(&tm);
error:
    errno = EINVAL;
    return -1; /* invalid month */
}

time_t vlc_http_msg_get_time(const struct vlc_http_msg *m, const char *name)
{
    const char *str = vlc_http_msg_get_header(m, name);
    if (str == NULL)
        return -1;
    return vlc_http_mktime(str);
}

time_t vlc_http_msg_get_atime(const struct vlc_http_msg *m)
{
    return vlc_http_msg_get_time(m, "Date");
}

time_t vlc_http_msg_get_mtime(const struct vlc_http_msg *m)
{
    return vlc_http_msg_get_time(m, "Last-Modified");
}

unsigned vlc_http_msg_get_retry_after(const struct vlc_http_msg *m)
{
    const char *str = vlc_http_msg_get_header(m, "Retry-After");
    if (str == NULL)
        return 0;

    char *end;
    unsigned long delay = strtoul(str, &end, 10);
    if (end != str && *end == '\0')
        return delay;

    time_t t = vlc_http_mktime(str);
    if (t != (time_t)-1)
    {
        time_t now;

        time(&now);
        if (t >= now)
            return t - now;
    }
    return 0;
}

uintmax_t vlc_http_msg_get_size(const struct vlc_http_msg *m)
{   /* IETF RFC7230 §3.3.3 */
    if ((m->status / 100) == 1 /* Informational 1xx (implicitly void) */
     || m->status == 204 /* No Content (implicitly void) */
     || m->status == 205 /* Reset Content (must be explicitly void) */
     || m->status == 304 /* Not Modified */)
        return 0;

    const char *str = vlc_http_msg_get_header(m, "Transfer-Encoding");
    if (str != NULL) /* Transfer-Encoding preempts Content-Length */
        return -1;

    str = vlc_http_msg_get_header(m, "Content-Length");
    if (str == NULL)
    {
        if (m->status < 0)
            return 0; /* Requests are void by default */
        return -1; /* Response of unknown size (e.g. chunked) */
    }

    uintmax_t length;

    if (sscanf(str, "%" SCNuMAX, &length) == 1)
        return length;

    errno = EINVAL;
    return -1;
}

void vlc_http_msg_get_cookies(const struct vlc_http_msg *m,
                              vlc_http_cookie_jar_t *jar,
                              const char *host, const char *path)
{
    if (jar == NULL)
        return;

    for (unsigned i = 0; i < m->count; i++)
        if (!strcasecmp(m->headers[i][0], "Set-Cookie"))
            vlc_http_cookies_store(jar, m->headers[i][1], host, path);
}

int vlc_http_msg_add_cookies(struct vlc_http_msg *m,
                             vlc_http_cookie_jar_t *jar)
{
    char *host, *cookies;
    int val = 0;
    bool secure;

    if (m->scheme == NULL || m->authority == NULL || m->path == NULL)
    {
        errno = EINVAL;
        return -1;
    }

    if (!strcasecmp(m->scheme, "https"))
        secure = true;
    else if (!strcasecmp(m->scheme, "http"))
        secure = false;
    else
        return 0;

    if (jar == NULL)
        return 0;

    if (m->authority[0] == '[')
        host = strndup(m->authority + 1, strcspn(m->authority + 1, "]"));
    else
        host = strndup(m->authority, strcspn(m->authority, ":"));
    if (unlikely(host == NULL))
        return -1;

    cookies = vlc_http_cookies_fetch(jar, secure, host, m->path);
    free(host);

    if (cookies != NULL)
    {
        val = vlc_http_msg_add_header(m, "Cookie", "%s", cookies);
        free(cookies);
    }
    return val;
}

char *vlc_http_msg_get_basic_realm(const struct vlc_http_msg *m)
{
    const char *auth;

    /* TODO: Support other authentication schemes. */
    /* NOTE: In principles, RFC7235 allows for multiple authentication schemes,
     * including multiple times Basic with a different realm each. There are no
     * UI paradigms though. */

    auth = vlc_http_msg_get_token(m, "WWW-Authenticate", "Basic");
    if (auth == NULL)
        return NULL;

    auth += 5;
    auth += strspn(auth, " "); /* 1*SP */

    return vlc_http_get_token_value(auth, "realm");
}

int vlc_http_msg_add_creds_basic(struct vlc_http_msg *m, bool proxy,
                                 const char *username, const char *password)
{
    char *str, *token;
    int ret;
    unsigned char c;

    /* CTL characters and colons not permitted in username */
    for (size_t len = 0; (c = username[len]) != '\0'; len++)
        if (c < 32 || c == 127 || c == ':')
        {
            errno = EINVAL;
            return -1;
        }

    /* CTL characters not permitted in password */
    for (size_t len = 0; (c = password[len]) != '\0'; len++)
        if (c < 32 || c == 127)
        {
            errno = EINVAL;
            return -1;
        }

    ret = asprintf(&str, "%s:%s", username, password);
    if (unlikely(ret < 0))
        return -1;

    token = vlc_b64_encode_binary((unsigned char *)str, ret);
    free(str);
    if (unlikely(token == NULL))
        return -1;

    ret = vlc_http_msg_add_header(m, proxy ? "Proxy-Authorization" :
                                  "Authorization", "Basic %s", token);
    free(token);
    return ret;
}

Messung
CHZG
849510093

¤ Dauer der Verarbeitung: 0.5 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104856
#Domains=417346