Initial import of Dillo

This commit is contained in:
2025-02-28 13:34:30 -05:00
parent bd4e3eebd8
commit 20fea64cb5
496 changed files with 156174 additions and 0 deletions

56
dpi/Makefile.am Normal file
View 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

File diff suppressed because it is too large Load Diff

1707
dpi/cookies.c Normal file

File diff suppressed because it is too large Load Diff

351
dpi/datauri.c Normal file
View 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

File diff suppressed because it is too large Load Diff

168
dpi/dpiutil.c Normal file
View 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[] =
{ "&amp;", "&lt;", "&gt;", "&quot;", "&#39;" };
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
View 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

File diff suppressed because it is too large Load Diff

354
dpi/ftp.c Normal file
View 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
View 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
View 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 == '<') ? "&lt;" : "&amp;");
}
} 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;
}