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