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