Split out http authentication handling into a separate file
[ffmpeg.git] / libavformat / httpauth.c
1 /*
2  * HTTP authentication
3  * Copyright (c) 2010 Martin Storsjo
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "httpauth.h"
23 #include "libavutil/base64.h"
24 #include "libavutil/avstring.h"
25 #include "avformat.h"
26 #include <ctype.h>
27
28 static void parse_key_value(const char *params,
29                             void (*callback_get_buf)(HTTPAuthState *state,
30                             const char *key, int key_len,
31                             char **dest, int *dest_len), HTTPAuthState *state)
32 {
33     const char *ptr = params;
34
35     /* Parse key=value pairs. */
36     for (;;) {
37         const char *key;
38         char *dest = NULL, *dest_end;
39         int key_len, dest_len = 0;
40
41         /* Skip whitespace and potential commas. */
42         while (*ptr && (isspace(*ptr) || *ptr == ','))
43             ptr++;
44         if (!*ptr)
45             break;
46
47         key = ptr;
48
49         if (!(ptr = strchr(key, '=')))
50             break;
51         ptr++;
52         key_len = ptr - key;
53
54         callback_get_buf(state, key, key_len, &dest, &dest_len);
55         dest_end = dest + dest_len - 1;
56
57         if (*ptr == '\"') {
58             ptr++;
59             while (*ptr && *ptr != '\"') {
60                 if (*ptr == '\\') {
61                     if (!ptr[1])
62                         break;
63                     if (dest && dest < dest_end)
64                         *dest++ = ptr[1];
65                     ptr += 2;
66                 } else {
67                     if (dest && dest < dest_end)
68                         *dest++ = *ptr;
69                     ptr++;
70                 }
71             }
72             if (*ptr == '\"')
73                 ptr++;
74         } else {
75             for (; *ptr && !(isspace(*ptr) || *ptr == ','); ptr++)
76                 if (dest && dest < dest_end)
77                     *dest++ = *ptr;
78         }
79         if (dest)
80             *dest = 0;
81     }
82 }
83
84 static void handle_basic_params(HTTPAuthState *state, const char *key,
85                                 int key_len, char **dest, int *dest_len)
86 {
87     if (!strncmp(key, "realm=", key_len)) {
88         *dest     =        state->realm;
89         *dest_len = sizeof(state->realm);
90     }
91 }
92
93 void ff_http_auth_handle_header(HTTPAuthState *state, const char *key,
94                                 const char *value)
95 {
96     if (!state)
97         return;
98
99     if (!strcmp(key, "WWW-Authenticate")) {
100         const char *p;
101         if (av_stristart(value, "Basic ", &p) &&
102             state->auth_type <= HTTP_AUTH_BASIC) {
103             state->auth_type = HTTP_AUTH_BASIC;
104             state->realm[0] = 0;
105             parse_key_value(p, handle_basic_params, state);
106         }
107     }
108 }
109
110 char *ff_http_auth_create_response(HTTPAuthState *state, const char *auth,
111                                    const char *path, const char *method)
112 {
113     char *authstr = NULL;
114
115     if (!auth || !strchr(auth, ':'))
116         return NULL;
117
118     if (state->auth_type == HTTP_AUTH_BASIC) {
119         int auth_b64_len = (strlen(auth) + 2) / 3 * 4 + 1;
120         int len = auth_b64_len + 30;
121         char *ptr;
122         authstr = av_malloc(len);
123         if (!authstr)
124             return NULL;
125         snprintf(authstr, len, "Authorization: Basic ");
126         ptr = authstr + strlen(authstr);
127         av_base64_encode(ptr, auth_b64_len, auth, strlen(auth));
128         av_strlcat(ptr, "\r\n", len);
129     }
130     return authstr;
131 }
132