1 /*
2 * Dpi for "View source".
3 *
4 * This server is an example. Play with it and modify to your taste.
5 *
6 * Copyright 2010-2015 Jorge Arellano Cid <jcid@dillo.org>
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
15 #include <unistd.h>
16 #include <sys/types.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include "../dpip/dpip.h"
22 #include "dpiutil.h"
23
24 /*
25 * Debugging macros
26 */
27 #define _MSG(...)
28 #define MSG(...) fprintf(stderr, "[vsource dpi]: " __VA_ARGS__)
29
30 /*---------------------------------------------------------------------------*/
31
32 const char *DOCTYPE=
33 "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>";
34
35
send_dpip_tag(Dsh * sh,char * dpip_tag)36 void send_dpip_tag(Dsh *sh, char *dpip_tag)
37 {
38 a_Dpip_dsh_write_str(sh, 0, "\nDpip tag received: ");
39 a_Dpip_dsh_write_str(sh, 0, dpip_tag ? dpip_tag : "None");
40 a_Dpip_dsh_write_str(sh, 1, "\n\n");
41 }
42
43 /*
44 * Send source as plain text
45 * (handles embedded null chars correctly).
46 */
send_plain_text(Dsh * sh,int data_size)47 void send_plain_text(Dsh *sh, int data_size)
48 {
49 char *token;
50 int bytes_read = 0, token_size;
51
52 /* Send HTTP header for plain text MIME type */
53 a_Dpip_dsh_write_str(sh, 0, "Content-type: text/plain\n\n");
54
55 while (bytes_read < data_size &&
56 (token = a_Dpip_dsh_read_token2(sh, 1, &token_size))) {
57 bytes_read += token_size;
58 _MSG("data_size=%d bytes_read=%d\n", data_size, bytes_read);
59 a_Dpip_dsh_write(sh, 1, token, token_size);
60 dFree(token);
61 }
62 }
63
64 /*
65 * Send source as plain text with line numbers
66 * (handles embedded null chars correctly).
67 */
send_numbered_text(Dsh * sh,int data_size)68 void send_numbered_text(Dsh *sh, int data_size)
69 {
70 int bytes_read = 0, line = 1, token_size = 0;
71 char *p, *q, *token, line_str[32];
72
73 /* Send HTTP header for plain text MIME type */
74 a_Dpip_dsh_write_str(sh, 0, "Content-type: text/plain\n\n");
75
76 while (bytes_read < data_size &&
77 (token = a_Dpip_dsh_read_token2(sh, 1, &token_size))) {
78 bytes_read += token_size;
79 p = q = token;
80
81 while (*p) {
82 snprintf(line_str, 32, "%2d: ", line);
83 a_Dpip_dsh_write_str(sh, 0, line_str);
84 if ((p = strpbrk(q, "\r\n"))) {
85 a_Dpip_dsh_write(sh, 0, q, p - q + 1);
86 if (*p == '\r' && p[1] == '\n')
87 ++p;
88 ++line;
89 } else {
90 /* send all the rest */
91 a_Dpip_dsh_write(sh, 1, q, token_size - (q - token));
92 break;
93 }
94 q = ++p;
95 }
96 dFree(token);
97 }
98 }
99
100 /*
101 * Send source as html text with line numbers
102 * (handles embedded null chars correctly).
103 */
send_html_text(Dsh * sh,const char * url,int data_size)104 void send_html_text(Dsh *sh, const char *url, int data_size)
105 {
106 int bytes_read = 0, old_line = 0, line = 1, token_size = 0;
107 char *p, *q, *token, line_str[128];
108
109 if (dStrnAsciiCasecmp(url, "dpi:", 4) == 0 &&
110 strncmp(url+4, "/vsource/:", 10) == 0)
111 url += 14;
112
113 /* Send HTTP header for html text MIME type */
114 a_Dpip_dsh_write_str(sh, 0, "Content-type: text/html\n\n");
115
116 a_Dpip_dsh_write_str(sh, 0, DOCTYPE);
117 a_Dpip_dsh_printf(sh, 0,
118 "\n"
119 "<html><head>\n"
120 "<title>Source for %s</title>\n"
121 "<style type=\"text/css\">\n"
122 " body {white-space: pre-wrap; font-family: monospace}\n"
123 " td.r1 {background-color:#B87333}\n"
124 " td.r2 {background-color:#DD7F32}\n"
125 "</style>\n"
126 "</head>\n"
127 "<body id=\"dillo_vs\">\n<table cellpadding='0'>\n", url);
128
129 while (bytes_read < data_size &&
130 (token = a_Dpip_dsh_read_token2(sh, 1, &token_size))) {
131 bytes_read += token_size;
132 p = q = token;
133
134 while (*p) {
135 if (line > old_line) {
136 snprintf(line_str, 128,
137 "<tr><td class='%s'>%d%s<td>",
138 (line & 1) ? "r1" : "r2", line,
139 (line == 1 || (line % 10) == 0) ? " " : "");
140 a_Dpip_dsh_write_str(sh, 0, line_str);
141 old_line = line;
142 }
143 if ((p = strpbrk(q, "\r\n<&"))) {
144 if (*p == '\r' || *p == '\n') {
145 a_Dpip_dsh_write(sh, 0, q, p - q + 1);
146 if (*p == '\r' && p[1] == '\n')
147 p++;
148 ++line;
149 } else {
150 a_Dpip_dsh_write(sh, 0, q, p - q);
151 a_Dpip_dsh_write_str(sh, 0, (*p == '<') ? "<" : "&");
152 }
153 } else {
154 /* send all the rest */
155 a_Dpip_dsh_write(sh, 1, q, token_size - (q - token));
156 break;
157 }
158 q = ++p;
159 }
160 dFree(token);
161 }
162
163 a_Dpip_dsh_write_str(sh, 1, "</table></body></html>");
164 }
165
166 /*
167 *
168 */
main(void)169 int main(void)
170 {
171 Dsh *sh;
172 int data_size;
173 char *dpip_tag, *cmd = NULL, *cmd2 = NULL, *url = NULL, *size_str = NULL;
174 char *d_cmd;
175
176 _MSG("starting...\n");
177 //sleep(20);
178
179 /* Initialize the SockHandler.
180 * This means we'll use stdin for input and stdout for output.
181 * In case of a server dpi, we'd use a socket and pass its file descriptor
182 * twice (e.g. a_Dpip_dsh_new(sock_fd, sock_fd, 1024).
183 * (Note: by now the last parameter is not used) */
184 sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 2*1024);
185
186 /* Authenticate our client...
187 * As we're using Internet domain sockets, DPIP checks whether the client
188 * runs with the user's ID, by means of a shared secret. The DPIP API does
189 * the work for us. */
190 if (!(dpip_tag = a_Dpip_dsh_read_token(sh, 1)) ||
191 a_Dpip_check_auth(dpip_tag) < 0) {
192 MSG("can't authenticate request: %s\n", dStrerror(errno));
193 a_Dpip_dsh_close(sh);
194 return 1;
195 }
196 dFree(dpip_tag);
197
198 /* Read the dpi command from STDIN
199 * Now we're past the authentication phase, let's see what's dillo
200 * asking from us. a_Dpip_dsh_read_token() will block and return
201 * a full dpip token or null on error (it's commented in dpip.c) */
202 dpip_tag = a_Dpip_dsh_read_token(sh, 1);
203 _MSG("tag = [%s]\n", dpip_tag);
204
205 /* Now that we have the dpip_tag, let's isolate the command and url */
206 cmd = a_Dpip_get_attr(dpip_tag, "cmd");
207 url = a_Dpip_get_attr(dpip_tag, "url");
208
209 /* Start sending our answer.
210 * (You can read the comments for DPIP API functions in dpip/dpip.c) */
211 d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
212 a_Dpip_dsh_write_str(sh, 0, d_cmd);
213 dFree(d_cmd);
214 dFree(dpip_tag);
215
216 dpip_tag = a_Dpip_dsh_read_token(sh, 1);
217 cmd2 = a_Dpip_get_attr(dpip_tag, "cmd");
218 if (cmd2) {
219 if (strcmp(cmd2, "start_send_page") == 0 &&
220 (size_str = a_Dpip_get_attr(dpip_tag, "data_size"))) {
221 data_size = strtol(size_str, NULL, 10);
222 /* Choose your flavour */
223 //send_plain_text(sh, data_size);
224 //send_numbered_text(sh, data_size);
225 send_html_text(sh, url, data_size);
226 } else if (strcmp(cmd2, "DpiError") == 0) {
227 /* Dillo detected an error (other failures just close the socket) */
228 a_Dpip_dsh_write_str(sh, 0, "Content-type: text/plain\n\n");
229 a_Dpip_dsh_write_str(sh, 1, "[vsource dpi]: "
230 "ERROR: Page not cached.\n");
231 }
232 dFree(cmd2);
233 }
234
235 dFree(cmd);
236 dFree(url);
237 dFree(size_str);
238 dFree(dpip_tag);
239
240 /* Finish the SockHandler */
241 a_Dpip_dsh_close(sh);
242 a_Dpip_dsh_free(sh);
243
244 return 0;
245 }
246
247