Dillo v3.1.1-91-g6d5b3ee3
Loading...
Searching...
No Matches
datauri.c
Go to the documentation of this file.
1/*
2 * File: datauri.c
3 *
4 * Copyright (C) 2006-2007 Jorge Arellano Cid <jcid@dillo.org>
5 *
6 * Filter dpi for the "data:" URI scheme (RFC 2397).
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <unistd.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <ctype.h>
19#include <errno.h>
20
21#include "../dpip/dpip.h"
22#include "dpiutil.h"
23#include "../src/misc.h"
24
25/*
26 * Debugging macros
27 */
28#define SILENT 1
29#define _MSG(...)
30#if SILENT
31 #define MSG(...)
32#else
33 #define MSG(...) fprintf(stderr, "[datauri dpi]: " __VA_ARGS__)
34#endif
35
36/*
37 * Global variables
38 */
39static Dsh *sh = NULL;
40
41static void b64strip_illegal_chars(unsigned char* str)
42{
43 unsigned char *p, *s = str;
44
45 MSG("len=%d{%s}\n", strlen((char*)str), str);
46
47 for (p = s; (*p = *s); ++s) {
48 if (d_isascii(*p) && (isalnum(*p) || strchr("+/=", *p)))
49 ++p;
50 }
51
52 MSG("len=%d{%s}\n", strlen((char *)str), str);
53}
54
55static int b64decode(unsigned char* str)
56{
57 unsigned char *cur, *start;
58 int d, dlast, phase;
59 unsigned char c;
60 static int table[256] = {
61 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
62 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
63 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
64 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
65 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
66 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
67 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
68 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
69 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
70 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
71 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
72 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
73 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
74 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
75 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
76 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
77 };
78
79 d = dlast = phase = 0;
80 start = str;
81 for (cur = str; *cur != '\0'; ++cur ) {
82 // jer: treat line endings as physical breaks.
83 //if (*cur == '\n' || *cur == '\r'){phase = dlast = 0; continue;}
84 d = table[(int)*cur];
85 if (d != -1) {
86 switch(phase) {
87 case 0:
88 ++phase;
89 break;
90 case 1:
91 c = ((dlast << 2) | ((d & 0x30) >> 4));
92 *str++ = c;
93 ++phase;
94 break;
95 case 2:
96 c = (((dlast & 0xf) << 4) | ((d & 0x3c) >> 2));
97 *str++ = c;
98 ++phase;
99 break;
100 case 3:
101 c = (((dlast & 0x03 ) << 6) | d);
102 *str++ = c;
103 phase = 0;
104 break;
105 }
106 dlast = d;
107 }
108 }
109 *str = '\0';
110 return str - start;
111}
112
113/* Modified from src/url.c --------------------------------------------------*/
114
115/*
116 * Given an hex octet (e.g., e3, 2F, 20), return the corresponding
117 * character if the octet is valid, and -1 otherwise
118 */
119static int Url_decode_hex_octet(const char *s)
120{
121 int hex_value;
122 char *tail, hex[3];
123
124 if (s && (hex[0] = s[0]) && (hex[1] = s[1])) {
125 hex[2] = 0;
126 hex_value = strtol(hex, &tail, 16);
127 if (tail - hex == 2)
128 return hex_value;
129 }
130 return -1;
131}
132
133/*
134 * Parse possible hexadecimal octets in the URI path.
135 * Returns a new allocated string.
136 */
137char *a_Url_decode_hex_str(const char *str, size_t *p_sz)
138{
139 char *new_str, *dest;
140 int i, val;
141
142 if (!str) {
143 *p_sz = 0;
144 return NULL;
145 }
146
147 dest = new_str = dNew(char, strlen(str) + 1);
148 for (i = 0; str[i]; i++) {
149 *dest++ = (str[i] == '%' && (val = Url_decode_hex_octet(str+i+1)) >= 0) ?
150 i+=2, val : str[i];
151 }
152 *dest = 0;
153
154 *p_sz = (size_t)(dest - new_str);
155 new_str = dRealloc(new_str, sizeof(char) * (dest - new_str + 1));
156 return new_str;
157}
158
159/* end ----------------------------------------------------------------------*/
160
161/*
162 * Send decoded data to dillo in an HTTP envelope.
163 */
164static void send_decoded_data(const char *url, const char *mime_type,
165 unsigned char *data, size_t data_sz)
166{
167 char *d_cmd;
168
169 /* Send dpip tag */
170 d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
171 a_Dpip_dsh_write_str(sh, 1, d_cmd);
172 dFree(d_cmd);
173
174 /* Send HTTP header. */
175 a_Dpip_dsh_write_str(sh, 0, "Content-type: ");
176 a_Dpip_dsh_write_str(sh, 0, mime_type);
177 a_Dpip_dsh_write_str(sh, 1, "\n\n");
178
179 /* Send message */
180 a_Dpip_dsh_write(sh, 0, (char *)data, data_sz);
181}
182
183static void send_failure_message(const char *url, const char *mime_type,
184 unsigned char *data, size_t data_sz)
185{
186 char *d_cmd;
187 char buf[1024];
188
189 const char *msg =
190"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n"
191"<html><body>\n"
192"<hr><h1>Datauri dpi</h1><hr>\n"
193"<p><b>Can't parse datauri:</b><br>\n";
194 const char *msg_mime_type="text/html";
195
196 /* Send dpip tag */
197 d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
198 a_Dpip_dsh_write_str(sh, 1, d_cmd);
199 dFree(d_cmd);
200
201 /* Send HTTP header. */
202 a_Dpip_dsh_write_str(sh, 0, "Content-type: ");
203 a_Dpip_dsh_write_str(sh, 0, msg_mime_type);
204 a_Dpip_dsh_write_str(sh, 1, "\n\n");
205
206 /* Send message */
207 a_Dpip_dsh_write_str(sh, 0, msg);
208
209 /* send some debug info */
210 snprintf(buf, 1024, "mime_type: %s<br>data size: %d<br>data: %s<br>",
211 mime_type, (int)data_sz, data);
212 a_Dpip_dsh_write_str(sh, 0, buf);
213
214 /* close page */
215 a_Dpip_dsh_write_str(sh, 0, "</body></html>");
216}
217
218/*
219 * Get mime type from the data URI.
220 */
221static char *datauri_get_mime(char *url)
222{
223 char buf[256];
224 char *mime_type = NULL, *p;
225 size_t len = 0;
226
227 if (dStrnAsciiCasecmp(url, "data:", 5) == 0) {
228 if ((p = strchr(url, ',')) && p - url < 256) {
229 url += 5;
230 len = p - url;
231 strncpy(buf, url, len);
232 buf[len] = 0;
233 /* strip ";base64" */
234 if (len >= 7 && dStrAsciiCasecmp(buf + len - 7, ";base64") == 0) {
235 len -= 7;
236 buf[len] = 0;
237 }
238 }
239
240 /* that's it, now handle omitted types */
241 if (len == 0) {
242 mime_type = dStrdup("text/plain;charset=US-ASCII");
243 } else if (!dStrnAsciiCasecmp(buf, "charset", 7)) {
244 mime_type = dStrconcat("text/plain;", buf, NULL);
245 } else {
246 mime_type = dStrdup(buf);
247 }
248 }
249
250 return mime_type;
251}
252
253/*
254 * Return a decoded data string.
255 */
256static unsigned char *datauri_get_data(char *url, size_t *p_sz)
257{
258 char *p;
259 int is_base64 = 0;
260 unsigned char *data = NULL;
261
262 if ((p = strchr(url, ',')) && p - url >= 12 && /* "data:;base64" */
263 dStrnAsciiCasecmp(p - 7, ";base64", 7) == 0) {
264 is_base64 = 1;
265 }
266
267 if (p) {
268 ++p;
269 if (is_base64) {
270 data = (unsigned char *)Unescape_uri_str(p);
272 *p_sz = (size_t) b64decode(data);
273 } else {
274 data = (unsigned char *)a_Url_decode_hex_str(p, p_sz);
275 }
276 } else {
277 data = (unsigned char *)dStrdup("");
278 *p_sz = 0;
279 }
280
281 return data;
282}
283
284/*
285 *
286 */
287int main(void)
288{
289 char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *mime_type;
290 unsigned char *data;
291 int rc;
292 size_t data_size = 0;
293
294 /* Initialize the SockHandler */
295 sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 8*1024);
296
297 rc = chdir("/tmp");
298 if (rc == -1) {
299 MSG("paths: error changing directory to /tmp: %s\n",
300 dStrerror(errno));
301 }
302
303 /* Authenticate our client... */
304 if (!(dpip_tag = a_Dpip_dsh_read_token(sh, 1)) ||
305 a_Dpip_check_auth(dpip_tag) < 0) {
306 MSG("can't authenticate request: %s\n", dStrerror(errno));
308 return 1;
309 }
310 dFree(dpip_tag);
311
312 /* Read the dpi command from STDIN */
313 dpip_tag = a_Dpip_dsh_read_token(sh, 1);
314 MSG("[%s]\n", dpip_tag);
315
316 cmd = a_Dpip_get_attr(dpip_tag, "cmd");
317 url = a_Dpip_get_attr(dpip_tag, "url");
318 if (!cmd || !url) {
319 MSG("Error, cmd=%s, url=%s\n", cmd, url);
320 exit (EXIT_FAILURE);
321 }
322
323 /* Parse the data URI */
324 mime_type = datauri_get_mime(url);
325 data = datauri_get_data(url, &data_size);
326
327 MSG("mime_type: %s\n", mime_type);
328 MSG("data_size: %d\n", (int)data_size);
329 MSG("data: {%s}\n", data);
330
331 if (mime_type && data) {
332 /* good URI */
333 send_decoded_data(url, mime_type, data, data_size);
334 } else {
335 /* malformed URI */
336 send_failure_message(url, mime_type, data, data_size);
337 }
338
339 dFree(data);
340 dFree(mime_type);
341 dFree(url);
342 dFree(cmd);
343 dFree(dpip_tag);
344
345 /* Finish the SockHandler */
348
349 return 0;
350}
351
static int b64decode(unsigned char *str)
Definition datauri.c:55
static unsigned char * datauri_get_data(char *url, size_t *p_sz)
Definition datauri.c:256
static Dsh * sh
Definition datauri.c:39
static int Url_decode_hex_octet(const char *s)
Definition datauri.c:119
#define MSG(...)
Definition datauri.c:31
int main(void)
Definition datauri.c:287
static void send_failure_message(const char *url, const char *mime_type, unsigned char *data, size_t data_sz)
Definition datauri.c:183
static void b64strip_illegal_chars(unsigned char *str)
Definition datauri.c:41
static void send_decoded_data(const char *url, const char *mime_type, unsigned char *data, size_t data_sz)
Definition datauri.c:164
char * a_Url_decode_hex_str(const char *str, size_t *p_sz)
Definition datauri.c:137
static char * datauri_get_mime(char *url)
Definition datauri.c:221
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
Definition dlib.c:102
void dFree(void *mem)
Definition dlib.c:68
int dStrAsciiCasecmp(const char *s1, const char *s2)
Definition dlib.c:203
char * dStrdup(const char *s)
Definition dlib.c:77
int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
Definition dlib.c:215
void * dRealloc(void *mem, size_t size)
Definition dlib.c:53
#define dStrerror
Definition dlib.h:95
#define dNew(type, count)
Definition dlib.h:49
void a_Dpip_dsh_free(Dsh *dsh)
Free the SockHandler structure.
Definition dpip.c:525
char * a_Dpip_build_cmd(const char *format,...)
Printf like function for building dpip commands.
Definition dpip.c:83
int a_Dpip_dsh_write_str(Dsh *dsh, int flush, const char *str)
Convenience function.
Definition dpip.c:374
char * a_Dpip_get_attr(const char *tag, const char *attrname)
Task: given a tag and an attribute name, return its value.
Definition dpip.c:192
char * a_Dpip_dsh_read_token(Dsh *dsh, int blocking)
Return a newlly allocated string with the next dpip token in the socket.
Definition dpip.c:493
void a_Dpip_dsh_close(Dsh *dsh)
Close this socket for reading and writing.
Definition dpip.c:504
int a_Dpip_check_auth(const char *auth_tag)
Check whether the given 'auth' string equals what dpid saved.
Definition dpip.c:201
int a_Dpip_dsh_write(Dsh *dsh, int flush, const char *Data, int DataSize)
Streamed write to socket.
Definition dpip.c:317
Dsh * a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
Create and initialize a dpip socket handler.
Definition dpip.c:247
char * Unescape_uri_str(const char *s)
Definition dpiutil.c:64
#define d_isascii(c)
Definition misc.h:11
Dpip socket handler type.
Definition dpip.h:31