Initial import of Dillo
This commit is contained in:
56
dpi/Makefile.am
Normal file
56
dpi/Makefile.am
Normal file
@ -0,0 +1,56 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)
|
||||
|
||||
bookmarksdir = $(libdir)/dillo/dpi/bookmarks
|
||||
downloadsdir = $(libdir)/dillo/dpi/downloads
|
||||
ftpdir = $(libdir)/dillo/dpi/ftp
|
||||
hellodir = $(libdir)/dillo/dpi/hello
|
||||
vsourcedir = $(libdir)/dillo/dpi/vsource
|
||||
filedir = $(libdir)/dillo/dpi/file
|
||||
cookiesdir = $(libdir)/dillo/dpi/cookies
|
||||
datauridir = $(libdir)/dillo/dpi/datauri
|
||||
bookmarks_PROGRAMS = bookmarks.dpi
|
||||
downloads_PROGRAMS = downloads.dpi
|
||||
ftp_PROGRAMS = ftp.filter.dpi
|
||||
hello_PROGRAMS = hello.filter.dpi
|
||||
vsource_PROGRAMS = vsource.filter.dpi
|
||||
file_PROGRAMS = file.dpi
|
||||
cookies_PROGRAMS = cookies.dpi
|
||||
datauri_PROGRAMS = datauri.filter.dpi
|
||||
|
||||
bookmarks_dpi_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
downloads_dpi_LDADD = @LIBFLTK_LIBS@ \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
ftp_filter_dpi_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
hello_filter_dpi_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
vsource_filter_dpi_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
file_dpi_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
cookies_dpi_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
datauri_filter_dpi_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
|
||||
downloads_dpi_CXXFLAGS = @LIBFLTK_CXXFLAGS@
|
||||
|
||||
bookmarks_dpi_SOURCES = bookmarks.c dpiutil.c dpiutil.h
|
||||
downloads_dpi_SOURCES = downloads.cc dpiutil.c dpiutil.h
|
||||
ftp_filter_dpi_SOURCES = ftp.c dpiutil.c dpiutil.h
|
||||
hello_filter_dpi_SOURCES = hello.c dpiutil.c dpiutil.h
|
||||
vsource_filter_dpi_SOURCES = vsource.c dpiutil.c dpiutil.h
|
||||
file_dpi_SOURCES = file.c dpiutil.c dpiutil.h
|
||||
cookies_dpi_SOURCES = cookies.c dpiutil.c dpiutil.h
|
||||
datauri_filter_dpi_SOURCES = datauri.c dpiutil.c dpiutil.h
|
||||
|
1680
dpi/bookmarks.c
Normal file
1680
dpi/bookmarks.c
Normal file
File diff suppressed because it is too large
Load Diff
1707
dpi/cookies.c
Normal file
1707
dpi/cookies.c
Normal file
File diff suppressed because it is too large
Load Diff
351
dpi/datauri.c
Normal file
351
dpi/datauri.c
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* File: datauri.c
|
||||
*
|
||||
* Copyright (C) 2006-2007 Jorge Arellano Cid <jcid@dillo.org>
|
||||
*
|
||||
* Filter dpi for the "data:" URI scheme (RFC 2397).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../dpip/dpip.h"
|
||||
#include "dpiutil.h"
|
||||
#include "../src/misc.h"
|
||||
|
||||
/*
|
||||
* Debugging macros
|
||||
*/
|
||||
#define SILENT 1
|
||||
#define _MSG(...)
|
||||
#if SILENT
|
||||
#define MSG(...)
|
||||
#else
|
||||
#define MSG(...) fprintf(stderr, "[datauri dpi]: " __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
static Dsh *sh = NULL;
|
||||
|
||||
static void b64strip_illegal_chars(unsigned char* str)
|
||||
{
|
||||
unsigned char *p, *s = str;
|
||||
|
||||
MSG("len=%d{%s}\n", strlen((char*)str), str);
|
||||
|
||||
for (p = s; (*p = *s); ++s) {
|
||||
if (d_isascii(*p) && (isalnum(*p) || strchr("+/=", *p)))
|
||||
++p;
|
||||
}
|
||||
|
||||
MSG("len=%d{%s}\n", strlen((char *)str), str);
|
||||
}
|
||||
|
||||
static int b64decode(unsigned char* str)
|
||||
{
|
||||
unsigned char *cur, *start;
|
||||
int d, dlast, phase;
|
||||
unsigned char c;
|
||||
static int table[256] = {
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
|
||||
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
|
||||
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
|
||||
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
|
||||
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
|
||||
};
|
||||
|
||||
d = dlast = phase = 0;
|
||||
start = str;
|
||||
for (cur = str; *cur != '\0'; ++cur ) {
|
||||
// jer: treat line endings as physical breaks.
|
||||
//if (*cur == '\n' || *cur == '\r'){phase = dlast = 0; continue;}
|
||||
d = table[(int)*cur];
|
||||
if (d != -1) {
|
||||
switch(phase) {
|
||||
case 0:
|
||||
++phase;
|
||||
break;
|
||||
case 1:
|
||||
c = ((dlast << 2) | ((d & 0x30) >> 4));
|
||||
*str++ = c;
|
||||
++phase;
|
||||
break;
|
||||
case 2:
|
||||
c = (((dlast & 0xf) << 4) | ((d & 0x3c) >> 2));
|
||||
*str++ = c;
|
||||
++phase;
|
||||
break;
|
||||
case 3:
|
||||
c = (((dlast & 0x03 ) << 6) | d);
|
||||
*str++ = c;
|
||||
phase = 0;
|
||||
break;
|
||||
}
|
||||
dlast = d;
|
||||
}
|
||||
}
|
||||
*str = '\0';
|
||||
return str - start;
|
||||
}
|
||||
|
||||
/* Modified from src/url.c --------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Given an hex octet (e.g., e3, 2F, 20), return the corresponding
|
||||
* character if the octet is valid, and -1 otherwise
|
||||
*/
|
||||
static int Url_decode_hex_octet(const char *s)
|
||||
{
|
||||
int hex_value;
|
||||
char *tail, hex[3];
|
||||
|
||||
if (s && (hex[0] = s[0]) && (hex[1] = s[1])) {
|
||||
hex[2] = 0;
|
||||
hex_value = strtol(hex, &tail, 16);
|
||||
if (tail - hex == 2)
|
||||
return hex_value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse possible hexadecimal octets in the URI path.
|
||||
* Returns a new allocated string.
|
||||
*/
|
||||
char *a_Url_decode_hex_str(const char *str, size_t *p_sz)
|
||||
{
|
||||
char *new_str, *dest;
|
||||
int i, val;
|
||||
|
||||
if (!str) {
|
||||
*p_sz = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dest = new_str = dNew(char, strlen(str) + 1);
|
||||
for (i = 0; str[i]; i++) {
|
||||
*dest++ = (str[i] == '%' && (val = Url_decode_hex_octet(str+i+1)) >= 0) ?
|
||||
i+=2, val : str[i];
|
||||
}
|
||||
*dest = 0;
|
||||
|
||||
*p_sz = (size_t)(dest - new_str);
|
||||
new_str = dRealloc(new_str, sizeof(char) * (dest - new_str + 1));
|
||||
return new_str;
|
||||
}
|
||||
|
||||
/* end ----------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Send decoded data to dillo in an HTTP envelope.
|
||||
*/
|
||||
static void send_decoded_data(const char *url, const char *mime_type,
|
||||
unsigned char *data, size_t data_sz)
|
||||
{
|
||||
char *d_cmd;
|
||||
|
||||
/* Send dpip tag */
|
||||
d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
|
||||
a_Dpip_dsh_write_str(sh, 1, d_cmd);
|
||||
dFree(d_cmd);
|
||||
|
||||
/* Send HTTP header. */
|
||||
a_Dpip_dsh_write_str(sh, 0, "Content-type: ");
|
||||
a_Dpip_dsh_write_str(sh, 0, mime_type);
|
||||
a_Dpip_dsh_write_str(sh, 1, "\n\n");
|
||||
|
||||
/* Send message */
|
||||
a_Dpip_dsh_write(sh, 0, (char *)data, data_sz);
|
||||
}
|
||||
|
||||
static void send_failure_message(const char *url, const char *mime_type,
|
||||
unsigned char *data, size_t data_sz)
|
||||
{
|
||||
char *d_cmd;
|
||||
char buf[1024];
|
||||
|
||||
const char *msg =
|
||||
"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n"
|
||||
"<html><body>\n"
|
||||
"<hr><h1>Datauri dpi</h1><hr>\n"
|
||||
"<p><b>Can't parse datauri:</b><br>\n";
|
||||
const char *msg_mime_type="text/html";
|
||||
|
||||
/* Send dpip tag */
|
||||
d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
|
||||
a_Dpip_dsh_write_str(sh, 1, d_cmd);
|
||||
dFree(d_cmd);
|
||||
|
||||
/* Send HTTP header. */
|
||||
a_Dpip_dsh_write_str(sh, 0, "Content-type: ");
|
||||
a_Dpip_dsh_write_str(sh, 0, msg_mime_type);
|
||||
a_Dpip_dsh_write_str(sh, 1, "\n\n");
|
||||
|
||||
/* Send message */
|
||||
a_Dpip_dsh_write_str(sh, 0, msg);
|
||||
|
||||
/* send some debug info */
|
||||
snprintf(buf, 1024, "mime_type: %s<br>data size: %d<br>data: %s<br>",
|
||||
mime_type, (int)data_sz, data);
|
||||
a_Dpip_dsh_write_str(sh, 0, buf);
|
||||
|
||||
/* close page */
|
||||
a_Dpip_dsh_write_str(sh, 0, "</body></html>");
|
||||
}
|
||||
|
||||
/*
|
||||
* Get mime type from the data URI.
|
||||
*/
|
||||
static char *datauri_get_mime(char *url)
|
||||
{
|
||||
char buf[256];
|
||||
char *mime_type = NULL, *p;
|
||||
size_t len = 0;
|
||||
|
||||
if (dStrnAsciiCasecmp(url, "data:", 5) == 0) {
|
||||
if ((p = strchr(url, ',')) && p - url < 256) {
|
||||
url += 5;
|
||||
len = p - url;
|
||||
strncpy(buf, url, len);
|
||||
buf[len] = 0;
|
||||
/* strip ";base64" */
|
||||
if (len >= 7 && dStrAsciiCasecmp(buf + len - 7, ";base64") == 0) {
|
||||
len -= 7;
|
||||
buf[len] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* that's it, now handle omitted types */
|
||||
if (len == 0) {
|
||||
mime_type = dStrdup("text/plain;charset=US-ASCII");
|
||||
} else if (!dStrnAsciiCasecmp(buf, "charset", 7)) {
|
||||
mime_type = dStrconcat("text/plain;", buf, NULL);
|
||||
} else {
|
||||
mime_type = dStrdup(buf);
|
||||
}
|
||||
}
|
||||
|
||||
return mime_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a decoded data string.
|
||||
*/
|
||||
static unsigned char *datauri_get_data(char *url, size_t *p_sz)
|
||||
{
|
||||
char *p;
|
||||
int is_base64 = 0;
|
||||
unsigned char *data = NULL;
|
||||
|
||||
if ((p = strchr(url, ',')) && p - url >= 12 && /* "data:;base64" */
|
||||
dStrnAsciiCasecmp(p - 7, ";base64", 7) == 0) {
|
||||
is_base64 = 1;
|
||||
}
|
||||
|
||||
if (p) {
|
||||
++p;
|
||||
if (is_base64) {
|
||||
data = (unsigned char *)Unescape_uri_str(p);
|
||||
b64strip_illegal_chars(data);
|
||||
*p_sz = (size_t) b64decode(data);
|
||||
} else {
|
||||
data = (unsigned char *)a_Url_decode_hex_str(p, p_sz);
|
||||
}
|
||||
} else {
|
||||
data = (unsigned char *)dStrdup("");
|
||||
*p_sz = 0;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *mime_type;
|
||||
unsigned char *data;
|
||||
int rc;
|
||||
size_t data_size = 0;
|
||||
|
||||
/* Initialize the SockHandler */
|
||||
sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 8*1024);
|
||||
|
||||
rc = chdir("/tmp");
|
||||
if (rc == -1) {
|
||||
MSG("paths: error changing directory to /tmp: %s\n",
|
||||
dStrerror(errno));
|
||||
}
|
||||
|
||||
/* Authenticate our client... */
|
||||
if (!(dpip_tag = a_Dpip_dsh_read_token(sh, 1)) ||
|
||||
a_Dpip_check_auth(dpip_tag) < 0) {
|
||||
MSG("can't authenticate request: %s\n", dStrerror(errno));
|
||||
a_Dpip_dsh_close(sh);
|
||||
return 1;
|
||||
}
|
||||
dFree(dpip_tag);
|
||||
|
||||
/* Read the dpi command from STDIN */
|
||||
dpip_tag = a_Dpip_dsh_read_token(sh, 1);
|
||||
MSG("[%s]\n", dpip_tag);
|
||||
|
||||
cmd = a_Dpip_get_attr(dpip_tag, "cmd");
|
||||
url = a_Dpip_get_attr(dpip_tag, "url");
|
||||
if (!cmd || !url) {
|
||||
MSG("Error, cmd=%s, url=%s\n", cmd, url);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Parse the data URI */
|
||||
mime_type = datauri_get_mime(url);
|
||||
data = datauri_get_data(url, &data_size);
|
||||
|
||||
MSG("mime_type: %s\n", mime_type);
|
||||
MSG("data_size: %d\n", (int)data_size);
|
||||
MSG("data: {%s}\n", data);
|
||||
|
||||
if (mime_type && data) {
|
||||
/* good URI */
|
||||
send_decoded_data(url, mime_type, data, data_size);
|
||||
} else {
|
||||
/* malformed URI */
|
||||
send_failure_message(url, mime_type, data, data_size);
|
||||
}
|
||||
|
||||
dFree(data);
|
||||
dFree(mime_type);
|
||||
dFree(url);
|
||||
dFree(cmd);
|
||||
dFree(dpip_tag);
|
||||
|
||||
/* Finish the SockHandler */
|
||||
a_Dpip_dsh_close(sh);
|
||||
a_Dpip_dsh_free(sh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
1128
dpi/downloads.cc
Normal file
1128
dpi/downloads.cc
Normal file
File diff suppressed because it is too large
Load Diff
168
dpi/dpiutil.c
Normal file
168
dpi/dpiutil.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* File: dpiutil.c
|
||||
*
|
||||
* Copyright 2004-2007 Jorge Arellano Cid <jcid@dillo.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "dpiutil.h"
|
||||
|
||||
/*
|
||||
* Debugging macros
|
||||
*/
|
||||
#define _MSG(...)
|
||||
#define MSG(...) printf("[dpiutil.c]: " __VA_ARGS__)
|
||||
|
||||
|
||||
/* Escaping/De-escaping ---------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Escape URI characters in 'esc_set' as %XX sequences.
|
||||
* Return value: New escaped string.
|
||||
*/
|
||||
char *Escape_uri_str(const char *str, const char *p_esc_set)
|
||||
{
|
||||
static const char *esc_set, *hex = "0123456789ABCDEF";
|
||||
char *p;
|
||||
Dstr *dstr;
|
||||
int i;
|
||||
|
||||
esc_set = (p_esc_set) ? p_esc_set : "%#:' ";
|
||||
dstr = dStr_sized_new(64);
|
||||
for (i = 0; str[i]; ++i) {
|
||||
if (str[i] <= 0x1F || str[i] == 0x7F || strchr(esc_set, str[i])) {
|
||||
dStr_append_c(dstr, '%');
|
||||
dStr_append_c(dstr, hex[(str[i] >> 4) & 15]);
|
||||
dStr_append_c(dstr, hex[str[i] & 15]);
|
||||
} else {
|
||||
dStr_append_c(dstr, str[i]);
|
||||
}
|
||||
}
|
||||
p = dstr->str;
|
||||
dStr_free(dstr, FALSE);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unescape %XX sequences in a string.
|
||||
* Return value: a new unescaped string
|
||||
*/
|
||||
char *Unescape_uri_str(const char *s)
|
||||
{
|
||||
char *p, *buf = dStrdup(s);
|
||||
|
||||
if (strchr(s, '%')) {
|
||||
for (p = buf; (*p = *s); ++s, ++p) {
|
||||
if (*p == '%' && isxdigit(s[1]) && isxdigit(s[2])) {
|
||||
*p = (isdigit(s[1]) ? (s[1] - '0')
|
||||
: D_ASCII_TOUPPER(s[1]) - 'A' + 10) * 16;
|
||||
*p += isdigit(s[2]) ? (s[2] - '0')
|
||||
: D_ASCII_TOUPPER(s[2]) - 'A' + 10;
|
||||
s += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static const char *unsafe_chars = "&<>\"'";
|
||||
static const char *unsafe_rep[] =
|
||||
{ "&", "<", ">", """, "'" };
|
||||
static const int unsafe_rep_len[] = { 5, 4, 4, 6, 5 };
|
||||
|
||||
/*
|
||||
* Escape unsafe characters as html entities.
|
||||
* Return value: New escaped string.
|
||||
*/
|
||||
char *Escape_html_str(const char *str)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
Dstr *dstr = dStr_sized_new(64);
|
||||
|
||||
for (i = 0; str[i]; ++i) {
|
||||
if ((p = strchr(unsafe_chars, str[i])))
|
||||
dStr_append(dstr, unsafe_rep[p - unsafe_chars]);
|
||||
else
|
||||
dStr_append_c(dstr, str[i]);
|
||||
}
|
||||
p = dstr->str;
|
||||
dStr_free(dstr, FALSE);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unescape a few HTML entities (inverse of Escape_html_str)
|
||||
* Return value: New unescaped string.
|
||||
*/
|
||||
char *Unescape_html_str(const char *str)
|
||||
{
|
||||
int i, j, k;
|
||||
char *u_str = dStrdup(str);
|
||||
|
||||
if (!strchr(str, '&'))
|
||||
return u_str;
|
||||
|
||||
for (i = 0, j = 0; str[i]; ++i) {
|
||||
if (str[i] == '&') {
|
||||
for (k = 0; k < 5; ++k) {
|
||||
if (!dStrnAsciiCasecmp(str + i, unsafe_rep[k], unsafe_rep_len[k])) {
|
||||
i += unsafe_rep_len[k] - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
u_str[j++] = (k < 5) ? unsafe_chars[k] : str[i];
|
||||
} else {
|
||||
u_str[j++] = str[i];
|
||||
}
|
||||
}
|
||||
u_str[j] = 0;
|
||||
|
||||
return u_str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Filter '\n', '\r', "%0D" and "%0A" from the authority part of an FTP url.
|
||||
* This helps to avoid a SMTP relaying hack. This filtering could be done
|
||||
* only when port == 25, but if the mail server is listening on another
|
||||
* port it wouldn't work.
|
||||
* Note: AFAIS this should be done by wget.
|
||||
*/
|
||||
char *Filter_smtp_hack(char *url)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
|
||||
if (strlen(url) > 6) { /* ftp:// */
|
||||
for (i = 6; (c = url[i]) && c != '/'; ++i) {
|
||||
if (c == '\n' || c == '\r') {
|
||||
memmove(url + i, url + i + 1, strlen(url + i));
|
||||
--i;
|
||||
} else if (c == '%' && url[i+1] == '0' &&
|
||||
(D_ASCII_TOLOWER(url[i+2]) == 'a' ||
|
||||
D_ASCII_TOLOWER(url[i+2]) == 'd')) {
|
||||
memmove(url + i, url + i + 3, strlen(url + i + 2));
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
66
dpi/dpiutil.h
Normal file
66
dpi/dpiutil.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* File: dpiutil.h
|
||||
*
|
||||
* Copyright 2004-2005 Jorge Arellano Cid <jcid@dillo.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains common functions used by dpi programs.
|
||||
* (i.e. a convenience library).
|
||||
*/
|
||||
|
||||
#ifndef __DPIUTIL_H__
|
||||
#define __DPIUTIL_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include "d_size.h"
|
||||
#include "../dlib/dlib.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
/*
|
||||
* Escape URI characters in 'esc_set' as %XX sequences.
|
||||
* Return value: New escaped string.
|
||||
*/
|
||||
char *Escape_uri_str(const char *str, const char *p_esc_set);
|
||||
|
||||
/*
|
||||
* Unescape %XX sequences in a string.
|
||||
* Return value: a new unescaped string
|
||||
*/
|
||||
char *Unescape_uri_str(const char *str);
|
||||
|
||||
/*
|
||||
* Escape unsafe characters as html entities.
|
||||
* Return value: New escaped string.
|
||||
*/
|
||||
char *Escape_html_str(const char *str);
|
||||
|
||||
/*
|
||||
* Unescape a few HTML entities (inverse of Escape_html_str)
|
||||
* Return value: New unescaped string.
|
||||
*/
|
||||
char *Unescape_html_str(const char *str);
|
||||
|
||||
/*
|
||||
* Filter an SMTP hack with a FTP URI
|
||||
*/
|
||||
char *Filter_smtp_hack(char *url);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __DPIUTIL_H__ */
|
||||
|
1138
dpi/file.c
Normal file
1138
dpi/file.c
Normal file
File diff suppressed because it is too large
Load Diff
354
dpi/ftp.c
Normal file
354
dpi/ftp.c
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Dpi for FTP.
|
||||
*
|
||||
* This server checks the ftp-URL to be a directory (requires wget).
|
||||
* If true, it sends back an html representation of it, and if not
|
||||
* a dpip message (which is caught by dillo who redirects the ftp URL
|
||||
* to the downloads server).
|
||||
*
|
||||
* Feel free to polish!
|
||||
*
|
||||
* Copyright 2003-2007 Jorge Arellano Cid <jcid@dillo.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Send feedback about the FTP login process from wget's stderr.
|
||||
* i.e. capture our child's stderr, process it, and report back.
|
||||
* - Handle simultaneous connections.
|
||||
* If ftp.dpi is implemented with a low level ftp library, it becomes
|
||||
* possible to keep the connection alive, and thus make browsing of ftp
|
||||
* directories faster (this avoids one login per page, and forks). Perhaps
|
||||
* it's not worth, but can be done.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../dpip/dpip.h"
|
||||
#include "dpiutil.h"
|
||||
#include "d_size.h"
|
||||
|
||||
/*
|
||||
* Debugging macros
|
||||
* (Set debugging messages to stderr, to see them)
|
||||
*/
|
||||
#define _MSG(...)
|
||||
//#define MSG(...) fprintf(stderr, "[ftp dpi]: " __VA_ARGS__)
|
||||
#define MSG(...) printf("[ftp dpi]: " __VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
static Dsh *sh = NULL;
|
||||
static char **dl_argv = NULL;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/* TODO: could use dStr ADT! */
|
||||
typedef struct {
|
||||
const char *str;
|
||||
int len;
|
||||
} ContentType_t;
|
||||
|
||||
static const ContentType_t MimeTypes[] = {
|
||||
{ "application/octet-stream", 24 },
|
||||
{ "text/html", 9 },
|
||||
{ "text/plain", 10 },
|
||||
{ "image/gif", 9 },
|
||||
{ "image/png", 9 },
|
||||
{ "image/jpeg", 10 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Detects 'Content-Type' from a data stream sample.
|
||||
*
|
||||
* It uses the magic(5) logic from file(1). Currently, it
|
||||
* only checks the few mime types that Dillo supports.
|
||||
*
|
||||
* 'Data' is a pointer to the first bytes of the raw data.
|
||||
*
|
||||
* Return value: (0 on success, 1 on doubt, 2 on lack of data).
|
||||
*/
|
||||
static int a_Misc_get_content_type_from_data2(void *Data, size_t Size,
|
||||
const char **PT)
|
||||
{
|
||||
int st = 1; /* default to "doubt' */
|
||||
int Type = 0; /* default to "application/octet-stream" */
|
||||
char *p = Data;
|
||||
uchar_t ch;
|
||||
size_t i, non_ascci;
|
||||
|
||||
/* HTML try */
|
||||
for (i = 0; i < Size && dIsspace(p[i]); ++i);
|
||||
if ((Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<html", 5)) ||
|
||||
(Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<head", 5)) ||
|
||||
(Size - i >= 6 && !dStrnAsciiCasecmp(p+i, "<title", 6)) ||
|
||||
(Size - i >= 14 && !dStrnAsciiCasecmp(p+i, "<!doctype html", 14)) ||
|
||||
/* this line is workaround for FTP through the Squid proxy */
|
||||
(Size - i >= 17 && !dStrnAsciiCasecmp(p+i, "<!-- HTML listing", 17))) {
|
||||
|
||||
Type = 1;
|
||||
st = 0;
|
||||
/* Images */
|
||||
} else if (Size >= 4 && !strncmp(p, "GIF8", 4)) {
|
||||
Type = 3;
|
||||
st = 0;
|
||||
} else if (Size >= 4 && !strncmp(p, "\x89PNG", 4)) {
|
||||
Type = 4;
|
||||
st = 0;
|
||||
} else if (Size >= 2 && !strncmp(p, "\xff\xd8", 2)) {
|
||||
/* JPEG has the first 2 bytes set to 0xffd8 in BigEndian - looking
|
||||
* at the character representation should be machine independent. */
|
||||
Type = 5;
|
||||
st = 0;
|
||||
|
||||
/* Text */
|
||||
} else {
|
||||
/* We'll assume "text/plain" if the set of chars above 127 is <= 10%
|
||||
* of the sample. This helps to catch ASCII, LATIN1 and UTF-8 as text.
|
||||
* Better heuristics are welcomed! :-) */
|
||||
non_ascci = 0;
|
||||
Size = MIN (Size, 256);
|
||||
for (i = 0; i < Size; i++) {
|
||||
ch = (uchar_t) p[i];
|
||||
if ((ch < 32 || ch > 126) && !dIsspace(ch))
|
||||
++non_ascci;
|
||||
}
|
||||
if (Size == 256) {
|
||||
Type = (non_ascci > Size/10) ? 0 : 2;
|
||||
st = 0;
|
||||
} else {
|
||||
Type = (non_ascci > Size/10) ? 0 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
*PT = MimeTypes[Type].str;
|
||||
return st;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Build a shell command using wget for this URL.
|
||||
*/
|
||||
static void make_wget_argv(char *url)
|
||||
{
|
||||
char *esc_url;
|
||||
|
||||
if (dl_argv) {
|
||||
dFree(dl_argv[3]);
|
||||
dFree(dl_argv);
|
||||
}
|
||||
dl_argv = dNew(char*, 10);
|
||||
|
||||
esc_url = Escape_uri_str(url, "'");
|
||||
/* avoid malicious SMTP relaying with FTP urls */
|
||||
Filter_smtp_hack(esc_url);
|
||||
|
||||
dl_argv[0] = "wget";
|
||||
dl_argv[1] = "-t1"; /* try once, default is 20 */
|
||||
dl_argv[2] = "-O-";
|
||||
dl_argv[3] = esc_url;
|
||||
dl_argv[4] = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fork, exec command, get its output and send via stdout.
|
||||
* Return: Number of bytes transferred, -1 if file-not_found, -2 if aborted.
|
||||
*/
|
||||
static int try_ftp_transfer(char *url)
|
||||
{
|
||||
#define MIN_SZ 256
|
||||
#define READ_SZ 16*1024
|
||||
|
||||
ssize_t n;
|
||||
int nb, has_mime_type, has_html_header, no_such_file, offer_download;
|
||||
const char *mime_type = "application/octet-stream";
|
||||
char buf[READ_SZ], *d_cmd;
|
||||
Dstr *dbuf = dStr_sized_new(READ_SZ);
|
||||
pid_t ch_pid;
|
||||
int aborted = 0;
|
||||
int DataPipe[2];
|
||||
|
||||
MSG("try_ftp_transfer: url=%s\n", url);
|
||||
|
||||
if (pipe(DataPipe) < 0) {
|
||||
MSG("pipe, %s\n", dStrerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prepare args for execvp() */
|
||||
make_wget_argv(url);
|
||||
|
||||
/* Start the child process */
|
||||
if ((ch_pid = fork()) == 0) {
|
||||
/* child */
|
||||
/* start wget */
|
||||
close(DataPipe[0]);
|
||||
dup2(DataPipe[1], 1); /* stdout */
|
||||
execvp(dl_argv[0], dl_argv);
|
||||
_exit(1);
|
||||
} else if (ch_pid < 0) {
|
||||
perror("fork, ");
|
||||
exit(1);
|
||||
} else {
|
||||
/* father continues below */
|
||||
close(DataPipe[1]);
|
||||
}
|
||||
|
||||
/* Read/Write the real data */
|
||||
nb = 0;
|
||||
has_mime_type = 0;
|
||||
has_html_header = 0;
|
||||
no_such_file = 0;
|
||||
offer_download = 0;
|
||||
do {
|
||||
while ((n = read(DataPipe[0], buf, READ_SZ)) < 0 && errno == EINTR);
|
||||
if (n > 0) {
|
||||
dStr_append_l(dbuf, buf, n);
|
||||
if (!has_mime_type && dbuf->len < MIN_SZ)
|
||||
continue;
|
||||
} else if (n < 0)
|
||||
break;
|
||||
|
||||
if (!has_mime_type) {
|
||||
if (dbuf->len == 0) {
|
||||
/* When the file doesn't exist, the transfer size is zero */
|
||||
no_such_file = 1;
|
||||
break;
|
||||
}
|
||||
a_Misc_get_content_type_from_data2(dbuf->str, dbuf->len, &mime_type);
|
||||
has_mime_type = 1;
|
||||
|
||||
if (strcmp(mime_type, "application/octet-stream") == 0) {
|
||||
/* abort transfer */
|
||||
kill(ch_pid, SIGTERM);
|
||||
/* The "application/octet-stream" MIME type will be sent and
|
||||
* Dillo will offer a download dialog */
|
||||
offer_download = 1;
|
||||
aborted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (offer_download || (!aborted && !has_html_header && dbuf->len)) {
|
||||
/* Send dpip tag */
|
||||
d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
|
||||
a_Dpip_dsh_write_str(sh, 1, d_cmd);
|
||||
dFree(d_cmd);
|
||||
|
||||
/* Send HTTP header. */
|
||||
a_Dpip_dsh_write_str(sh, 0, "Content-type: ");
|
||||
a_Dpip_dsh_write_str(sh, 0, mime_type);
|
||||
a_Dpip_dsh_write_str(sh, 1, "\r\n\r\n");
|
||||
has_html_header = 1;
|
||||
}
|
||||
|
||||
if (!aborted && dbuf->len) {
|
||||
a_Dpip_dsh_write(sh, 1, dbuf->str, dbuf->len);
|
||||
nb += dbuf->len;
|
||||
dStr_truncate(dbuf, 0);
|
||||
}
|
||||
} while (n > 0 && !aborted);
|
||||
|
||||
dStr_free(dbuf, 1);
|
||||
return (no_such_file ? -1 : (aborted ? -2 : nb));
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *err_msg = "404 Not Found\nNo such file or directory";
|
||||
char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *url2 = NULL;
|
||||
int st, rc;
|
||||
char *p, *d_cmd;
|
||||
|
||||
/* wget may need to write a temporary file... */
|
||||
rc = chdir("/tmp");
|
||||
if (rc == -1) {
|
||||
MSG("paths: error changing directory to /tmp: %s\n",
|
||||
dStrerror(errno));
|
||||
}
|
||||
|
||||
/* Initialize the SockHandler */
|
||||
sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 8*1024);
|
||||
|
||||
if (argc == 2) {
|
||||
/* Debugging with a command line argument */
|
||||
dpip_tag = dStrdup(argv[1]);
|
||||
} else {
|
||||
/* Authenticate our client... */
|
||||
if (!(dpip_tag = a_Dpip_dsh_read_token(sh, 1)) ||
|
||||
a_Dpip_check_auth(dpip_tag) < 0) {
|
||||
MSG("can't authenticate request: %s\n", dStrerror(errno));
|
||||
a_Dpip_dsh_close(sh);
|
||||
return 1;
|
||||
}
|
||||
dFree(dpip_tag);
|
||||
/* Read the dpi command from STDIN */
|
||||
dpip_tag = a_Dpip_dsh_read_token(sh, 1);
|
||||
}
|
||||
MSG("tag=[%s]\n", dpip_tag);
|
||||
|
||||
cmd = a_Dpip_get_attr(dpip_tag, "cmd");
|
||||
url = a_Dpip_get_attr(dpip_tag, "url");
|
||||
if (!cmd || !url) {
|
||||
MSG("ERROR, cmd=%s, url=%s\n", cmd, url);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ((st = try_ftp_transfer(url)) == -1) {
|
||||
/* Transfer failed, the requested file may not exist or be a symlink
|
||||
* to a directory. Try again... */
|
||||
if ((p = strrchr(url, '/')) && p[1] &&
|
||||
p > url && p[-1] != '/') {
|
||||
url2 = dStrconcat(url, "/", NULL);
|
||||
st = try_ftp_transfer(url2);
|
||||
}
|
||||
}
|
||||
|
||||
if (st == -1) {
|
||||
/* The transfer failed, let dillo know... */
|
||||
d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
|
||||
a_Dpip_dsh_write_str(sh, 0, d_cmd);
|
||||
dFree(d_cmd);
|
||||
a_Dpip_dsh_printf(sh, 1,
|
||||
"HTTP/1.1 404 Not Found\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"\r\n"
|
||||
"%s",
|
||||
strlen(err_msg), err_msg);
|
||||
}
|
||||
|
||||
dFree(cmd);
|
||||
dFree(url);
|
||||
dFree(url2);
|
||||
dFree(dpip_tag);
|
||||
|
||||
/* Finish the SockHandler */
|
||||
a_Dpip_dsh_close(sh);
|
||||
a_Dpip_dsh_free(sh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
190
dpi/hello.c
Normal file
190
dpi/hello.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Dpi for "Hello World".
|
||||
*
|
||||
* This server is an example. Play with it and modify to your taste.
|
||||
*
|
||||
* Copyright 2003-2007 Jorge Arellano Cid <jcid@dillo.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "../dpip/dpip.h"
|
||||
#include "dpiutil.h"
|
||||
|
||||
/*
|
||||
* Debugging macros
|
||||
*/
|
||||
#define _MSG(...)
|
||||
#define MSG(...) printf("[hello dpi]: " __VA_ARGS__)
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
FILE *in_stream;
|
||||
Dsh *sh;
|
||||
char *dpip_tag, *cmd = NULL, *url = NULL, *child_cmd = NULL;
|
||||
char *esc_tag, *d_cmd;
|
||||
size_t n;
|
||||
int ret;
|
||||
char buf[4096];
|
||||
char *choice[] = {"Window was closed", "Yes", "No",
|
||||
"Could be", "It's OK", "Cancel"};
|
||||
/* "Could>be", ">It's OK", "Can'>cel"}; --for testing */
|
||||
int choice_num = -1;
|
||||
|
||||
MSG("starting...\n");
|
||||
/* sleep(20) */
|
||||
|
||||
/* Initialize the SockHandler.
|
||||
* This means we'll use stdin for input and stdout for output.
|
||||
* In case of a server dpi, we'd use a socket and pass its file descriptor
|
||||
* twice (e.g. a_Dpip_dsh_new(sock_fd, sock_fd, 1024).
|
||||
* (Note: by now the last parameter is not used) */
|
||||
sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 2*1024);
|
||||
|
||||
/* Authenticate our client...
|
||||
* As we're using Internet domain sockets, DPIP checks whether the client
|
||||
* runs with the user's ID, by means of a shared secret. The DPIP API does
|
||||
* the work for us. */
|
||||
if (!(dpip_tag = a_Dpip_dsh_read_token(sh, 1)) ||
|
||||
a_Dpip_check_auth(dpip_tag) < 0) {
|
||||
MSG("can't authenticate request: %s\n", dStrerror(errno));
|
||||
a_Dpip_dsh_close(sh);
|
||||
return 1;
|
||||
}
|
||||
dFree(dpip_tag);
|
||||
|
||||
/* Read the dpi command from STDIN
|
||||
* Now we're past the authentication phase, let's see what's dillo
|
||||
* asking from us. a_Dpip_dsh_read_token() will block and return
|
||||
* a full dpip token or null on error (it's commented in dpip.c) */
|
||||
dpip_tag = a_Dpip_dsh_read_token(sh, 1);
|
||||
MSG("tag = [%s]\n", dpip_tag);
|
||||
|
||||
/* Now that we have the dpip_tag, let's isolate the command and url */
|
||||
cmd = a_Dpip_get_attr(dpip_tag, "cmd");
|
||||
url = a_Dpip_get_attr(dpip_tag, "url");
|
||||
|
||||
/*-- Dialog part */
|
||||
/* This is the dialog window. This is an example of interaction with
|
||||
* the user. If you're starting to understand dpis, comment this out
|
||||
* by switching to "#if 0" and the dialog will be disabled. */
|
||||
#if 1
|
||||
{
|
||||
char *dpip_tag2, *dialog_msg;
|
||||
|
||||
/* Let's confirm the request */
|
||||
/* NOTE: you can send less alternatives (e.g. only alt1 and alt2) */
|
||||
d_cmd = a_Dpip_build_cmd(
|
||||
"cmd=%s title=%s msg=%s alt1=%s alt2=%s alt3=%s alt4=%s alt5=%s",
|
||||
"dialog", "Dillo: Hello", "Do you want to see the hello page?",
|
||||
choice[1], choice[2], choice[3], choice[4], choice[5]);
|
||||
a_Dpip_dsh_write_str(sh, 1, d_cmd);
|
||||
dFree(d_cmd);
|
||||
|
||||
/* Get the answer */
|
||||
dpip_tag2 = a_Dpip_dsh_read_token(sh, 1);
|
||||
MSG("tag = [%s]\n", dpip_tag2);
|
||||
|
||||
/* Get "msg" value */
|
||||
dialog_msg = a_Dpip_get_attr(dpip_tag2, "msg");
|
||||
choice_num = 0;
|
||||
if (dialog_msg)
|
||||
choice_num = *dialog_msg - '0';
|
||||
|
||||
dFree(dialog_msg);
|
||||
dFree(dpip_tag2);
|
||||
}
|
||||
#endif
|
||||
/*-- EOD part */
|
||||
|
||||
/* Start sending our answer.
|
||||
* (You can read the comments for DPIP API functions in dpip/dpip.c) */
|
||||
d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
|
||||
a_Dpip_dsh_write_str(sh, 0, d_cmd);
|
||||
dFree(d_cmd);
|
||||
|
||||
a_Dpip_dsh_printf(sh, 0,
|
||||
"Content-type: text/html\n\n"
|
||||
"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n"
|
||||
"<html>\n"
|
||||
"<head><title>Simple dpi test page (hello.dpi)</title></head>\n"
|
||||
"<body><hr><h1>Hello world!</h1><hr>\n<br><br>\n");
|
||||
|
||||
/* Show the choice received with the dialog */
|
||||
a_Dpip_dsh_printf(sh, 0,
|
||||
"<hr>\n"
|
||||
"<table width='100%%' border='1' bgcolor='burlywood'><tr><td>\n"
|
||||
"<big><em>Dialog question:</em> Do you want to see the hello page?<br>\n"
|
||||
"<em>Answer received:</em> <b>%s</b></big> </table>\n"
|
||||
"<hr>\n",
|
||||
choice_num < 0 ? "There was NO dialog!" : choice[choice_num]);
|
||||
|
||||
/* Show the dpip tag we received */
|
||||
esc_tag = Escape_html_str(dpip_tag);
|
||||
a_Dpip_dsh_printf(sh, 0,
|
||||
"<h3>dpip tag received:</h3>\n"
|
||||
"<pre>\n%s</pre>\n"
|
||||
"<br><small>(<b>dpip:</b> dpi protocol)</small><br><br><br>\n",
|
||||
esc_tag);
|
||||
dFree(esc_tag);
|
||||
|
||||
|
||||
/* Now something more interesting,
|
||||
* fork a command and show its feedback.
|
||||
* (An example of generating dynamic content with an external
|
||||
* program). */
|
||||
if (cmd && url) {
|
||||
child_cmd = dStrdup("date -R");
|
||||
MSG("[%s]\n", child_cmd);
|
||||
|
||||
/* Fork, exec command, get its output and answer */
|
||||
if ((in_stream = popen(child_cmd, "r")) == NULL) {
|
||||
perror("popen");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
a_Dpip_dsh_write_str(sh, 0, "<h3>date:</h3>\n");
|
||||
a_Dpip_dsh_write_str(sh, 0, "<pre>\n");
|
||||
|
||||
/* Read/Write */
|
||||
while ((n = fread (buf, 1, 4096, in_stream)) > 0) {
|
||||
a_Dpip_dsh_write(sh, 0, buf, n);
|
||||
}
|
||||
|
||||
a_Dpip_dsh_write_str(sh, 0, "</pre>\n");
|
||||
|
||||
if ((ret = pclose(in_stream)) != 0)
|
||||
MSG("popen: [%d]\n", ret);
|
||||
|
||||
dFree(child_cmd);
|
||||
}
|
||||
|
||||
a_Dpip_dsh_write_str(sh, 1, "</body></html>\n");
|
||||
|
||||
dFree(cmd);
|
||||
dFree(url);
|
||||
dFree(dpip_tag);
|
||||
|
||||
/* Finish the SockHandler */
|
||||
a_Dpip_dsh_close(sh);
|
||||
a_Dpip_dsh_free(sh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
261
dpi/vsource.c
Normal file
261
dpi/vsource.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Dpi for "View source".
|
||||
*
|
||||
* This server is an example. Play with it and modify to your taste.
|
||||
*
|
||||
* Copyright 2010-2015 Jorge Arellano Cid <jcid@dillo.org>
|
||||
* Copyright 2024 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "../dpip/dpip.h"
|
||||
#include "dpiutil.h"
|
||||
|
||||
/*
|
||||
* Debugging macros
|
||||
*/
|
||||
#define _MSG(...)
|
||||
#define MSG(...) fprintf(stderr, "[vsource dpi]: " __VA_ARGS__)
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
const char *DOCTYPE=
|
||||
"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>";
|
||||
|
||||
|
||||
void send_dpip_tag(Dsh *sh, char *dpip_tag)
|
||||
{
|
||||
a_Dpip_dsh_write_str(sh, 0, "\nDpip tag received: ");
|
||||
a_Dpip_dsh_write_str(sh, 0, dpip_tag ? dpip_tag : "None");
|
||||
a_Dpip_dsh_write_str(sh, 1, "\n\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Send source as plain text
|
||||
* (handles embedded null chars correctly).
|
||||
*/
|
||||
void send_plain_text(Dsh *sh, int data_size)
|
||||
{
|
||||
char *token;
|
||||
int bytes_read = 0, token_size;
|
||||
|
||||
/* Send HTTP header for plain text MIME type */
|
||||
a_Dpip_dsh_write_str(sh, 0, "Content-type: text/plain\n\n");
|
||||
|
||||
while (bytes_read < data_size &&
|
||||
(token = a_Dpip_dsh_read_token2(sh, 1, &token_size))) {
|
||||
bytes_read += token_size;
|
||||
_MSG("data_size=%d bytes_read=%d\n", data_size, bytes_read);
|
||||
a_Dpip_dsh_write(sh, 1, token, token_size);
|
||||
dFree(token);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send source as plain text with line numbers
|
||||
* (handles embedded null chars correctly).
|
||||
*/
|
||||
void send_numbered_text(Dsh *sh, int data_size)
|
||||
{
|
||||
int bytes_read = 0, line = 1, token_size = 0;
|
||||
char *p, *q, *token, line_str[32];
|
||||
|
||||
/* Send HTTP header for plain text MIME type */
|
||||
a_Dpip_dsh_write_str(sh, 0, "Content-type: text/plain\n\n");
|
||||
|
||||
while (bytes_read < data_size &&
|
||||
(token = a_Dpip_dsh_read_token2(sh, 1, &token_size))) {
|
||||
bytes_read += token_size;
|
||||
p = q = token;
|
||||
|
||||
while (*p) {
|
||||
snprintf(line_str, 32, "%2d: ", line);
|
||||
a_Dpip_dsh_write_str(sh, 0, line_str);
|
||||
if ((p = strpbrk(q, "\r\n"))) {
|
||||
a_Dpip_dsh_write(sh, 0, q, p - q + 1);
|
||||
if (*p == '\r' && p[1] == '\n')
|
||||
++p;
|
||||
++line;
|
||||
} else {
|
||||
/* send all the rest */
|
||||
a_Dpip_dsh_write(sh, 1, q, token_size - (q - token));
|
||||
break;
|
||||
}
|
||||
q = ++p;
|
||||
}
|
||||
dFree(token);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send source as html text with line numbers
|
||||
* (handles embedded null chars correctly).
|
||||
*/
|
||||
void send_html_text(Dsh *sh, const char *url, int data_size)
|
||||
{
|
||||
int bytes_read = 0, old_line = 0, line = 1, token_size = 0;
|
||||
char *p, *q, *token, line_str[128];
|
||||
|
||||
if (dStrnAsciiCasecmp(url, "dpi:", 4) == 0 &&
|
||||
strncmp(url+4, "/vsource/:", 10) == 0)
|
||||
url += 14;
|
||||
|
||||
/* Send HTTP header for html text MIME type */
|
||||
a_Dpip_dsh_write_str(sh, 0, "Content-type: text/html\n\n");
|
||||
|
||||
a_Dpip_dsh_write_str(sh, 0, DOCTYPE);
|
||||
a_Dpip_dsh_printf(sh, 0,
|
||||
"\n"
|
||||
"<html><head>\n"
|
||||
"<title>Source for %s</title>\n"
|
||||
"<style type=\"text/css\">\n"
|
||||
" body {\n"
|
||||
" white-space: pre-wrap;\n"
|
||||
" font-family: monospace;\n"
|
||||
" margin: 0;\n"
|
||||
" width: 100%;\n"
|
||||
" }\n"
|
||||
" table { border:0 }\n"
|
||||
" td.num {\n"
|
||||
" padding-top: 1px;\n"
|
||||
" padding-bottom: 1px;\n"
|
||||
" padding-left: 0.5em;\n"
|
||||
" padding-right: 0.5em;\n"
|
||||
" text-align: right;\n"
|
||||
" border-right: 1px solid #999999;\n"
|
||||
" background-color: #c6c6c6;\n"
|
||||
" }"
|
||||
" td.src { padding-left:0.25em; }\n"
|
||||
" a { color: black; text-decoration:none; }\n"
|
||||
"</style>\n"
|
||||
"</head>\n"
|
||||
"<body id=\"dillo_vs\">\n<table cellspacing='0' cellpadding='0'>\n", url);
|
||||
|
||||
while (bytes_read < data_size &&
|
||||
(token = a_Dpip_dsh_read_token2(sh, 1, &token_size))) {
|
||||
bytes_read += token_size;
|
||||
p = q = token;
|
||||
|
||||
while (*p) {
|
||||
if (line > old_line) {
|
||||
snprintf(line_str, 128,
|
||||
"<tr><td class='num' id='L%d'><a href='#L%d'>%d</a><td class='src'>",
|
||||
line, line, line);
|
||||
a_Dpip_dsh_write_str(sh, 0, line_str);
|
||||
old_line = line;
|
||||
}
|
||||
if ((p = strpbrk(q, "\r\n<&"))) {
|
||||
if (*p == '\r' || *p == '\n') {
|
||||
a_Dpip_dsh_write(sh, 0, q, p - q + 1);
|
||||
if (*p == '\r' && p[1] == '\n')
|
||||
p++;
|
||||
++line;
|
||||
} else {
|
||||
a_Dpip_dsh_write(sh, 0, q, p - q);
|
||||
a_Dpip_dsh_write_str(sh, 0, (*p == '<') ? "<" : "&");
|
||||
}
|
||||
} else {
|
||||
/* send all the rest */
|
||||
a_Dpip_dsh_write(sh, 1, q, token_size - (q - token));
|
||||
break;
|
||||
}
|
||||
q = ++p;
|
||||
}
|
||||
dFree(token);
|
||||
}
|
||||
|
||||
a_Dpip_dsh_write_str(sh, 1, "</table></body></html>");
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
Dsh *sh;
|
||||
int data_size;
|
||||
char *dpip_tag, *cmd = NULL, *cmd2 = NULL, *url = NULL, *size_str = NULL;
|
||||
char *d_cmd;
|
||||
|
||||
_MSG("starting...\n");
|
||||
//sleep(20);
|
||||
|
||||
/* Initialize the SockHandler.
|
||||
* This means we'll use stdin for input and stdout for output.
|
||||
* In case of a server dpi, we'd use a socket and pass its file descriptor
|
||||
* twice (e.g. a_Dpip_dsh_new(sock_fd, sock_fd, 1024).
|
||||
* (Note: by now the last parameter is not used) */
|
||||
sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 2*1024);
|
||||
|
||||
/* Authenticate our client...
|
||||
* As we're using Internet domain sockets, DPIP checks whether the client
|
||||
* runs with the user's ID, by means of a shared secret. The DPIP API does
|
||||
* the work for us. */
|
||||
if (!(dpip_tag = a_Dpip_dsh_read_token(sh, 1)) ||
|
||||
a_Dpip_check_auth(dpip_tag) < 0) {
|
||||
MSG("can't authenticate request: %s\n", dStrerror(errno));
|
||||
a_Dpip_dsh_close(sh);
|
||||
return 1;
|
||||
}
|
||||
dFree(dpip_tag);
|
||||
|
||||
/* Read the dpi command from STDIN
|
||||
* Now we're past the authentication phase, let's see what's dillo
|
||||
* asking from us. a_Dpip_dsh_read_token() will block and return
|
||||
* a full dpip token or null on error (it's commented in dpip.c) */
|
||||
dpip_tag = a_Dpip_dsh_read_token(sh, 1);
|
||||
_MSG("tag = [%s]\n", dpip_tag);
|
||||
|
||||
/* Now that we have the dpip_tag, let's isolate the command and url */
|
||||
cmd = a_Dpip_get_attr(dpip_tag, "cmd");
|
||||
url = a_Dpip_get_attr(dpip_tag, "url");
|
||||
|
||||
/* Start sending our answer.
|
||||
* (You can read the comments for DPIP API functions in dpip/dpip.c) */
|
||||
d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
|
||||
a_Dpip_dsh_write_str(sh, 0, d_cmd);
|
||||
dFree(d_cmd);
|
||||
dFree(dpip_tag);
|
||||
|
||||
dpip_tag = a_Dpip_dsh_read_token(sh, 1);
|
||||
cmd2 = a_Dpip_get_attr(dpip_tag, "cmd");
|
||||
if (cmd2) {
|
||||
if (strcmp(cmd2, "start_send_page") == 0 &&
|
||||
(size_str = a_Dpip_get_attr(dpip_tag, "data_size"))) {
|
||||
data_size = strtol(size_str, NULL, 10);
|
||||
/* Choose your flavour */
|
||||
//send_plain_text(sh, data_size);
|
||||
//send_numbered_text(sh, data_size);
|
||||
send_html_text(sh, url, data_size);
|
||||
} else if (strcmp(cmd2, "DpiError") == 0) {
|
||||
/* Dillo detected an error (other failures just close the socket) */
|
||||
a_Dpip_dsh_write_str(sh, 0, "Content-type: text/plain\n\n");
|
||||
a_Dpip_dsh_write_str(sh, 1, "[vsource dpi]: "
|
||||
"ERROR: Page not cached.\n");
|
||||
}
|
||||
dFree(cmd2);
|
||||
}
|
||||
|
||||
dFree(cmd);
|
||||
dFree(url);
|
||||
dFree(size_str);
|
||||
dFree(dpip_tag);
|
||||
|
||||
/* Finish the SockHandler */
|
||||
a_Dpip_dsh_close(sh);
|
||||
a_Dpip_dsh_free(sh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user