Merge pull request #1112 from oliverschmidt/master

Various improvements of the HTTP client and web browser.
This commit is contained in:
Oliver Schmidt 2015-06-14 16:12:24 +02:00
commit c9edb9006b
15 changed files with 215 additions and 158 deletions

View File

@ -9,7 +9,6 @@ html_a "a\0"
html_body "body\0"
html_br "br\0"
html_form "form\0"
html_frame "frame\0"
html_h1 "h1\0"
html_h2 "h2\0"
html_h3 "h3\0"

View File

@ -31,9 +31,6 @@ const char html_br[4] =
const char html_form[6] =
/* "form\0" */
{0x66, 0x6f, 0x72, 0x6d, 00, };
const char html_frame[7] =
/* "frame\0" */
{0x66, 0x72, 0x61, 0x6d, 0x65, 00, };
const char html_h1[4] =
/* "h1\0" */
{0x68, 0x31, 00, };

View File

@ -9,7 +9,6 @@ extern const char html_a[3];
extern const char html_body[6];
extern const char html_br[4];
extern const char html_form[6];
extern const char html_frame[7];
extern const char html_h1[4];
extern const char html_h2[4];
extern const char html_h3[4];

View File

@ -119,9 +119,6 @@ G * (<br>, <p>, <h>), the <li> tag (but does not even try to
#define ISO_eq 0x3d
#define ISO_gt 0x3e
#define ISO_rbrack 0x5b
#define ISO_lbrack 0x5d
#define MINORSTATE_NONE 0
#define MINORSTATE_TEXT 1 /* Parse normal text */
#define MINORSTATE_EXTCHAR 2 /* Check for semi-colon */
@ -140,7 +137,7 @@ G * (<br>, <p>, <h>), the <li> tag (but does not even try to
#define MAJORSTATE_LINK 2
#define MAJORSTATE_FORM 3
#define MAJORSTATE_DISCARD 4
#define MAJORSTATE_SCRIPT 5
struct htmlparser_state {
@ -151,7 +148,7 @@ struct htmlparser_state {
unsigned char tagattrptr;
char tagattrparam[WWW_CONF_MAX_URLLEN + 1];
unsigned char tagattrparamptr;
unsigned char lastchar, quotechar;
unsigned char quotechar;
unsigned char majorstate, lastmajorstate;
char linkurl[WWW_CONF_MAX_URLLEN + 1];
@ -196,33 +193,31 @@ static const char *tags[] = {
html_br,
#define TAG_FORM 10
html_form,
#define TAG_FRAME 11
html_frame,
#define TAG_H1 12
#define TAG_H1 11
html_h1,
#define TAG_H2 13
#define TAG_H2 12
html_h2,
#define TAG_H3 14
#define TAG_H3 13
html_h3,
#define TAG_H4 15
#define TAG_H4 14
html_h4,
#define TAG_IMG 16
#define TAG_IMG 15
html_img,
#define TAG_INPUT 17
#define TAG_INPUT 16
html_input,
#define TAG_LI 18
#define TAG_LI 17
html_li,
#define TAG_P 19
#define TAG_P 18
html_p,
#define TAG_SCRIPT 20
#define TAG_SCRIPT 19
html_script,
#define TAG_SELECT 21
#define TAG_SELECT 20
html_select,
#define TAG_STYLE 22
#define TAG_STYLE 21
html_style,
#define TAG_TR 23
#define TAG_TR 22
html_tr,
#define TAG_LAST 24
#define TAG_LAST 23
last,
};
@ -254,7 +249,7 @@ htmlparser_init(void)
{
s.majorstate = s.lastmajorstate = MAJORSTATE_DISCARD;
s.minorstate = MINORSTATE_TEXT;
s.lastchar = 0;
s.wordlen = 0;
#if WWW_CONF_FORMS
s.formaction[0] = 0;
#endif /* WWW_CONF_FORMS */
@ -305,10 +300,10 @@ do_word(void)
{
if(s.wordlen > 0) {
if(s.majorstate == MAJORSTATE_LINK) {
if(s.word[s.wordlen] != ISO_space) {
if(s.word[s.wordlen - 1] != ISO_space) {
add_char(ISO_space);
}
} else if(s.majorstate == MAJORSTATE_DISCARD) {
} else if(s.majorstate >= MAJORSTATE_DISCARD) {
s.wordlen = 0;
} else {
s.word[s.wordlen] = '\0';
@ -368,13 +363,19 @@ static void
parse_tag(void)
{
static char *tagattrparam;
static unsigned char tag;
static unsigned char size;
static char dummy;
tag = find_tag(s.tag);
/* If we are inside a <script> we mustn't interpret any tags
(inside JavaScript strings) but wait for the </script>. */
if(s.majorstate == MAJORSTATE_SCRIPT && tag != TAG_SLASHSCRIPT) {
return;
}
PRINTF(("Parsing tag '%s' '%s' '%s'\n", s.tag, s.tagattr, s.tagattrparam));
switch(find_tag(s.tag)) {
switch(tag) {
case TAG_P:
case TAG_H1:
case TAG_H2:
@ -386,15 +387,18 @@ parse_tag(void)
case TAG_TR:
case TAG_SLASHDIV:
case TAG_SLASHH:
dummy = 0;
newline();
break;
case TAG_LI:
if(s.tagattr[0] == 0) {
newline();
add_char(ISO_asterisk);
add_char(ISO_space);
}
break;
case TAG_SCRIPT:
switch_majorstate(MAJORSTATE_SCRIPT);
break;
case TAG_STYLE:
case TAG_SELECT:
switch_majorstate(MAJORSTATE_DISCARD);
@ -408,18 +412,6 @@ parse_tag(void)
case TAG_BODY:
s.majorstate = s.lastmajorstate = MAJORSTATE_BODY;
break;
case TAG_FRAME:
if(strncmp(s.tagattr, html_src, sizeof(html_src)) == 0 && s.tagattrparam[0] != 0) {
switch_majorstate(MAJORSTATE_BODY);
newline();
add_char(ISO_rbrack);
do_word();
htmlparser_link((char *)html_frame, (unsigned char)strlen(html_frame), s.tagattrparam);
PRINTF(("Frame [%s]\n", s.tagattrparam));
add_char(ISO_lbrack);
newline();
}
break;
case TAG_IMG:
if(strncmp(s.tagattr, html_alt, sizeof(html_alt)) == 0 && s.tagattrparam[0] != 0) {
add_char(ISO_lt);
@ -572,6 +564,15 @@ parse_word(char *data, uint8_t dlen)
}
break;
case MINORSTATE_TAG:
/* If we are inside a <srcipt> we mustn't mistake a JavaScript
equation with a '<' as a tag. So we check for the very next
character to be a '/' as we're only interested in parsing
the </script>. */
if(s.majorstate == MAJORSTATE_SCRIPT && data[0] != ISO_slash) {
s.minorstate = MINORSTATE_TEXT;
break;
}
/* We are currently parsing within the name of a tag. We check
for the end of a tag (the '>' character) or whitespace (which
indicates that we should parse a tag attr argument

View File

@ -1,4 +1,5 @@
http_http "http://"
http_https "https://"
http_200 "200 "
http_301 "301 "
http_302 "302 "
@ -10,3 +11,4 @@ http_location "location: "
http_host "Host: "
http_crnl "\r\n"
http_html ".html"
http_redirect "<body>Redirect to "

View File

@ -1,6 +1,9 @@
const char http_http[8] =
/* "http://" */
{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, };
const char http_https[9] =
/* "https://" */
{0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, };
const char http_200[5] =
/* "200 " */
{0x32, 0x30, 0x30, 0x20, };
@ -34,3 +37,6 @@ const char http_crnl[3] =
const char http_html[6] =
/* ".html" */
{0x2e, 0x68, 0x74, 0x6d, 0x6c, };
const char http_redirect[19] =
/* "<body>Redirect to " */
{0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x20, 0x74, 0x6f, 0x20, };

View File

@ -1,4 +1,5 @@
extern const char http_http[8];
extern const char http_https[9];
extern const char http_200[5];
extern const char http_301[5];
extern const char http_302[5];
@ -10,3 +11,4 @@ extern const char http_location[11];
extern const char http_host[7];
extern const char http_crnl[3];
extern const char http_html[6];
extern const char http_redirect[19];

View File

@ -49,7 +49,7 @@
#define HTTPFLAG_NONE 0
#define HTTPFLAG_OK 1
#define HTTPFLAG_MOVED 2
#define HTTPFLAG_ERROR 3
#define HTTPFLAG_HTTPS 3
#define ISO_nl 0x0a
@ -63,11 +63,11 @@ struct webclient_state {
uint16_t port;
char host[40];
char file[WWW_CONF_MAX_URLLEN];
char file[WWW_CONF_MAX_URLLEN - 10]; // URL - "http://<host>/"
uint16_t getrequestptr;
uint16_t getrequestleft;
char httpheaderline[200];
char httpheaderline[WWW_CONF_MAX_URLLEN + 10]; // URL + "Location: "
uint16_t httpheaderlineptr;
char mimetype[32];
@ -327,13 +327,12 @@ parse_headers(uint16_t len)
char *cptr;
static unsigned char i;
while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) {
while(len > 0) {
s.httpheaderline[s.httpheaderlineptr] = *(char *)uip_appdata;
uip_appdata = (char *)uip_appdata + 1;
--len;
if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) {
/* We have an entire HTTP header line in s.httpheaderline, so
we parse it. */
/* We reached the end of an HTTP header line. */
if(s.httpheaderline[0] == ISO_cr) {
/* This was the last header line (i.e., and empty "\r\n"), so
we are done with the headers and proceed with the actual
@ -342,6 +341,9 @@ parse_headers(uint16_t len)
return len;
}
if(s.httpheaderlineptr < sizeof(s.httpheaderline) - 1) {
/* We have an entire HTTP header line in s.httpheaderline, so
we parse it. */
s.httpheaderline[s.httpheaderlineptr - 1] = 0;
/* Check for specific HTTP header fields. */
if(casecmp(s.httpheaderline, http_content_type,
@ -358,7 +360,9 @@ parse_headers(uint16_t len)
cptr = s.httpheaderline +
sizeof(http_location) - 1;
if(strncmp(cptr, http_http, 7) == 0) {
if(strncmp(cptr, http_https, sizeof(http_https) - 1) == 0) {
s.httpflag = HTTPFLAG_HTTPS;
} else if(strncmp(cptr, http_http, 7) == 0) {
cptr += 7;
for(i = 0; i < s.httpheaderlineptr - 7; ++i) {
if(*cptr == 0 ||
@ -375,15 +379,17 @@ parse_headers(uint16_t len)
strncpy(s.file, cptr, sizeof(s.file));
/* s.file[s.httpheaderlineptr - i] = 0;*/
}
}
/* We're done parsing, so we reset the pointer and start the
next line. */
s.httpheaderlineptr = 0;
} else {
if(s.httpheaderlineptr < sizeof(s.httpheaderline) - 1) {
++s.httpheaderlineptr;
}
}
}
return len;
}
/*-----------------------------------------------------------------------------------*/
@ -403,7 +409,7 @@ newdata(void)
}
if(len > 0 && s.state == WEBCLIENT_STATE_DATA &&
s.httpflag != HTTPFLAG_MOVED) {
s.httpflag == HTTPFLAG_OK) {
webclient_datahandler((char *)uip_appdata, len);
}
}
@ -441,7 +447,6 @@ webclient_appcall(void *state)
return;
}
/* The acked() and newdata() functions may alter the uip_appdata
ptr, so we need to store it in the "dataptr" variable so that we
can restore it before the senddata() function is called. */
@ -474,10 +479,18 @@ webclient_appcall(void *state)
if(uip_closed()) {
tcp_markconn(uip_conn, NULL);
if(s.httpflag != HTTPFLAG_MOVED) {
switch(s.httpflag) {
case HTTPFLAG_HTTPS:
/* Send some info to the user. */
webclient_datahandler((char *)http_redirect, sizeof(http_redirect) - 1);
webclient_datahandler(s.file, strlen(s.file));
webclient_datahandler((char *)http_crnl, sizeof(http_crnl) - 1);
/* FALLTHROUGH */
case HTTPFLAG_OK:
/* Send NULL data to signal EOF. */
webclient_datahandler(NULL, 0);
} else {
break;
case HTTPFLAG_MOVED:
/* conn = uip_connect(uip_conn->ripaddr, s.port);
if(conn != NULL) {
dispatcher_markconn(conn, NULL);
@ -489,6 +502,7 @@ webclient_appcall(void *state)
}
#endif /* UIP_UDP */
webclient_get(s.host, s.port, s.file);
break;
}
}
}

View File

@ -125,7 +125,7 @@ static struct ctk_button wgetyesbutton =
#if WWW_CONF_HISTORY_SIZE > 0
/* The char arrays that hold the history of visited URLs. */
static char history[WWW_CONF_HISTORY_SIZE][WWW_CONF_MAX_URLLEN];
static char history_last;
static unsigned char history_last;
#endif /* WWW_CONF_HISTORY_SIZE > 0 */
struct linkattrib {
@ -170,6 +170,7 @@ static struct inputattrib *currptr;
#define ISO_nl 0x0a
#define ISO_space 0x20
#define ISO_hash 0x23
#define ISO_ampersand 0x26
#define ISO_plus 0x2b
#define ISO_slash 0x2f
@ -181,6 +182,7 @@ static char *webpageptr;
static unsigned char x, y;
static unsigned char loading;
static unsigned short firsty, pagey;
static unsigned char newlines;
static unsigned char count;
static char receivingmsgs[4][23] = {
@ -194,7 +196,7 @@ PROCESS(www_process, "Web browser");
AUTOSTART_PROCESSES(&www_process);
static void CC_FASTCALL formsubmit(struct formattrib *form);
static void CC_FASTCALL formsubmit(struct inputattrib *trigger);
/*-----------------------------------------------------------------------------------*/
/* make_window()
@ -277,6 +279,7 @@ start_loading(void)
loading = 1;
x = y = 0;
pagey = 0;
newlines = 0;
webpageptr = webpage;
clear_page();
@ -305,10 +308,13 @@ open_url(void)
static uip_ipaddr_t addr;
/* Trim off any spaces in the end of the url. */
urlptr = url + strlen(url) - 1;
while(*urlptr == ' ' && urlptr > url) {
*urlptr = 0;
--urlptr;
urlptr = url + strlen(url);
while(urlptr > url) {
if(*(urlptr - 1) == ' ') {
*--urlptr = 0;
} else {
break;
}
}
/* Don't even try to go further if the URL is empty. */
@ -376,7 +382,6 @@ open_url(void)
} else {
show_statustext("Connecting...");
}
redraw_window();
}
/*-----------------------------------------------------------------------------------*/
/* set_link(link):
@ -510,15 +515,17 @@ PROCESS_THREAD(www_process, ev, data)
firsty = 0;
start_loading();
--history_last;
/* Note: history_last is unsigned ! */
if(history_last > WWW_CONF_HISTORY_SIZE) {
history_last = WWW_CONF_HISTORY_SIZE - 1;
}
memcpy(url, history[(int)history_last], WWW_CONF_MAX_URLLEN);
*history[(int)history_last] = 0;
open_url();
CTK_WIDGET_FOCUS(&mainwindow, &backbutton);
#endif /* WWW_CONF_HISTORY_SIZE > 0 */
} else if(w == (struct ctk_widget *)&downbutton) {
firsty = pagey + WWW_CONF_WEBPAGE_HEIGHT - 4;
firsty = pagey + WWW_CONF_WEBPAGE_HEIGHT - 2;
start_loading();
open_url();
CTK_WIDGET_FOCUS(&mainwindow, &downbutton);
@ -557,9 +564,8 @@ PROCESS_THREAD(www_process, ev, data)
#if WWW_CONF_FORMS
} else {
/* Assume form widget. */
struct inputattrib *input = (struct inputattrib *)
(((char *)w) - offsetof(struct inputattrib, widget));
formsubmit(input->formptr);
formsubmit((struct inputattrib *)
(((char *)w) - offsetof(struct inputattrib, widget)));
#endif /* WWW_CONF_FORMS */
}
} else if(ev == ctk_signal_hyperlink_activate) {
@ -670,8 +676,6 @@ webclient_connected(void)
{
start_loading();
clear_page();
show_statustext("Request sent...");
set_url(webclient_hostname(), webclient_port(), webclient_filename());
@ -731,6 +735,8 @@ add_pagewidget(char *text, unsigned char size, char *attrib, unsigned char type,
char *wptr;
static unsigned char maxwidth;
newlines = 0;
if(!loading) {
return;
}
@ -837,6 +843,10 @@ htmlparser_newline(void)
{
char *wptr;
if(++newlines > 2) {
return;
}
if(pagey < firsty) {
++pagey;
x = 0;
@ -863,6 +873,8 @@ htmlparser_newline(void)
void
htmlparser_word(char *word, unsigned char wordlen)
{
newlines = 0;
if(loading) {
if(wordlen + 1 > WWW_CONF_WEBPAGE_WIDTH - x) {
htmlparser_newline();
@ -886,8 +898,13 @@ htmlparser_word(char *word, unsigned char wordlen)
void
htmlparser_link(char *text, unsigned char textlen, char *url)
{
/* No link for https or fragment-only as we would't be able to handle it anyway. */
if(url[0] == ISO_hash || strncmp(url, http_https, sizeof(http_https) - 1) == 0) {
htmlparser_word(text, textlen);
} else {
add_pagewidget(text, textlen, url, CTK_WIDGET_HYPERLINK, 0);
}
}
/*-----------------------------------------------------------------------------------*/
#if WWW_CONF_FORMS
void
@ -946,23 +963,36 @@ add_query(char delimiter, char *string)
}
/*-----------------------------------------------------------------------------------*/
static void CC_FASTCALL
formsubmit(struct formattrib *form)
formsubmit(struct inputattrib *trigger)
{
struct inputattrib *inputptr;
struct inputattrib *input;
struct formattrib *form = trigger->formptr;
char delimiter = ISO_questionmark;
set_link(form->action);
for(inputptr = form->nextptr; inputptr != NULL; inputptr = inputptr->nextptr) {
/* No button pressed so prepare to look for default button. */
if(trigger->widget.type == CTK_WIDGET_TEXTENTRY) {
trigger = NULL;
}
for(input = form->nextptr; input != NULL; input = input->nextptr) {
char *name;
char *value;
if(inputptr->widget.type == CTK_WIDGET_BUTTON) {
name = ((struct submitattrib *)inputptr)->name;
value = ((struct submitattrib *)inputptr)->button.text;
if(input->widget.type == CTK_WIDGET_TEXTENTRY) {
name = ((struct textattrib *)input)->name;
value = ((struct textattrib *)input)->textentry.text;
} else {
name = ((struct textattrib *)inputptr)->name;
value = ((struct textattrib *)inputptr)->textentry.text;
/* Consider first button as default button. */
if(trigger == NULL) {
trigger = input;
}
if(input != trigger) {
continue;
}
name = ((struct submitattrib *)input)->name;
value = ((struct submitattrib *)input)->button.text;
}
add_query(delimiter, name);

View File

@ -44,7 +44,7 @@
#define WWW_CONF_HISTORY_SIZE 10
#endif
#ifndef WWW_CONF_MAX_URLLEN
#define WWW_CONF_MAX_URLLEN 300
#define WWW_CONF_MAX_URLLEN 255
#endif
#ifndef WWW_CONF_PAGEATTRIB_SIZE
#define WWW_CONF_PAGEATTRIB_SIZE 2000

View File

@ -1,4 +1,5 @@
http_http "http://"
http_https "https://"
http_200 "200 "
http_301 "301 "
http_302 "302 "
@ -32,4 +33,4 @@ http_gif ".gif"
http_jpg ".jpg"
http_text ".text"
http_txt ".txt"
http_redirect "<body>Redirect to "

View File

@ -1,6 +1,9 @@
const char http_http[8] =
/* "http://" */
{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, };
const char http_https[9] =
/* "https://" */
{0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, };
const char http_200[5] =
/* "200 " */
{0x32, 0x30, 0x30, 0x20, };
@ -100,3 +103,6 @@ const char http_text[6] =
const char http_txt[5] =
/* ".txt" */
{0x2e, 0x74, 0x78, 0x74, };
const char http_redirect[19] =
/* "<body>Redirect to " */
{0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x20, 0x74, 0x6f, 0x20, };

View File

@ -1,4 +1,5 @@
extern const char http_http[8];
extern const char http_https[9];
extern const char http_200[5];
extern const char http_301[5];
extern const char http_302[5];
@ -32,3 +33,4 @@ extern const char http_gif[5];
extern const char http_jpg[5];
extern const char http_text[6];
extern const char http_txt[5];
extern const char http_redirect[19];

View File

@ -72,7 +72,6 @@ typedef unsigned short uip_stats_t;
#define UIP_CONF_LLH_LEN 14
#define RESOLV_CONF_SUPPORTS_MDNS 0
#define RESOLV_CONF_SUPPORTS_RECORD_EXPIRATION 0
#define NETSTACK_CONF_RDC_CHANNEL_CHECK_RATE 1
#define LOADER_CONF_ARCH "lib/unload.h"

View File

@ -56,11 +56,8 @@ typedef long s32_t;
typedef unsigned short uip_stats_t;
#define UIP_CONF_MAX_CONNECTIONS 40
#define UIP_CONF_MAX_LISTENPORTS 40
#define UIP_CONF_LLH_LEN 14
#define UIP_CONF_BUFFER_SIZE 1514
#define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN
#define UIP_CONF_TCP_SPLIT 1
#define UIP_CONF_LOGGING 1
#define UIP_CONF_UDP_CHECKSUMS 1
@ -77,6 +74,8 @@ typedef unsigned short uip_stats_t;
#define UIP_CONF_IP_FORWARD 1
#endif
#define RESOLV_CONF_SUPPORTS_MDNS 0
#define RESOLV_CONF_SUPPORTS_RECORD_EXPIRATION 0
#include <ctype.h>
#define ctk_arch_isprint isprint