/* next_sciptstate: * * Reads one line of script and decides what to do next. */ static void next_scriptstate(void) { struct httpd_fs_file fsfile; u8_t i; again: switch(hs->script[0]) { case ISO_t: /* Send a text string. */ hs->state = HTTP_TEXT; hs->dataptr = &hs->script[2]; /* Calculate length of string. */ for(i = 0; hs->dataptr[i] != ISO_nl; ++i); hs->count = i; break; case ISO_c: /* Call a function. */ hs->state = HTTP_FUNC; hs->dataptr = NULL; hs->count = 0; uip_reset_acked(); break; case ISO_i: /* Include a file. */ hs->state = HTTP_FILE; if(!httpd_fs_open(&hs->script[2], &fsfile)) { uip_abort(); dealloc_state(hs); } hs->dataptr = fsfile.data; hs->count = fsfile.len; break; case ISO_hash: /* Comment line. */ next_scriptline(); goto again; break; case ISO_period: /* End of script. */ hs->state = HTTP_END; uip_close(); dealloc_state(hs); break; default: uip_abort(); dealloc_state(hs); break; } }
/*-----------------------------------------------------------------------------------*/ void httpd_appcall(void) { struct fs_file fsfile; u8_t i; switch(uip_conn->lport) { /* This is the web server: */ case HTONS(httpPORT): /* Pick out the application state from the uip_conn structure. */ hs = (struct httpd_state *)(uip_conn->appstate); /* We use the uip_ test functions to deduce why we were called. If uip_connected() is non-zero, we were called because a remote host has connected to us. If uip_newdata() is non-zero, we were called because the remote host has sent us new data, and if uip_acked() is non-zero, the remote host has acknowledged the data we previously sent to it. */ if(uip_connected()) { /* Since we have just been connected with the remote host, we reset the state for this connection. The ->count variable contains the amount of data that is yet to be sent to the remote host, and the ->state is set to HTTP_NOGET to signal that we haven't received any HTTP GET request for this connection yet. */ hs->state = HTTP_NOGET; hs->count = 0; return; } else if(uip_poll()) { /* If we are polled ten times, we abort the connection. This is because we don't want connections lingering indefinately in the system. */ if(hs->count++ >= 10) { uip_abort(); } return; } else if(uip_newdata() && hs->state == HTTP_NOGET) { /* This is the first data we receive, and it should contain a GET. */ /* Check for GET. */ if(uip_appdata[0] != ISO_G || uip_appdata[1] != ISO_E || uip_appdata[2] != ISO_T || uip_appdata[3] != ISO_space) { /* If it isn't a GET, we abort the connection. */ uip_abort(); return; } /* Find the file we are looking for. */ for(i = 4; i < 40; ++i) { if(uip_appdata[i] == ISO_space || uip_appdata[i] == ISO_cr || uip_appdata[i] == ISO_nl) { uip_appdata[i] = 0; break; } } PRINT("request for file "); PRINTLN(&uip_appdata[4]); /* Check for a request for "/". */ if(uip_appdata[4] == ISO_slash && uip_appdata[5] == 0) { fs_open(file_index_html.name, &fsfile); } else { if(!fs_open((const char *)&uip_appdata[4], &fsfile)) { PRINTLN("couldn't open file"); fs_open(file_404_html.name, &fsfile); } } if(uip_appdata[4] == ISO_slash && uip_appdata[5] == ISO_c && uip_appdata[6] == ISO_g && uip_appdata[7] == ISO_i && uip_appdata[8] == ISO_slash) { /* If the request is for a file that starts with "/cgi/", we prepare for invoking a script. */ hs->script = fsfile.data; next_scriptstate(); } else { hs->script = NULL; /* The web server is now no longer in the HTTP_NOGET state, but in the HTTP_FILE state since is has now got the GET from the client and will start transmitting the file. */ hs->state = HTTP_FILE; /* Point the file pointers in the connection state to point to the first byte of the file. */ hs->dataptr = fsfile.data; hs->count = fsfile.len; } } if(hs->state != HTTP_FUNC) { /* Check if the client (remote end) has acknowledged any data that we've previously sent. If so, we move the file pointer further into the file and send back more data. If we are out of data to send, we close the connection. */ if(uip_acked()) { if(hs->count >= uip_conn->len) { hs->count -= uip_conn->len; hs->dataptr += uip_conn->len; } else { hs->count = 0; } if(hs->count == 0) { if(hs->script != NULL) { next_scriptline(); next_scriptstate(); } else { uip_close(); } } } } else { /* Call the CGI function. */ if(cgitab[hs->script[2] - ISO_a](uip_acked())) { /* If the function returns non-zero, we jump to the next line in the script. */ next_scriptline(); next_scriptstate(); } } if(hs->state != HTTP_FUNC && !uip_poll()) { /* Send a piece of data, but not more than the MSS of the connection. */ uip_send(( void * ) hs->dataptr, hs->count); } /* Finally, return to uIP. Our outgoing packet will soon be on its way... */ return; default: /* Should never happen. */ uip_abort(); break; } }
/*-----------------------------------------------------------------------------------*/ DISPATCHER_UIPCALL(httpd_appcall, state) { struct httpd_fs_file fsfile; u8_t i; DISPATCHER_UIPCALL_ARG(state); hs = (struct httpd_state *)(state); /* We use the uip_ test functions to deduce why we were called. If uip_connected() is non-zero, we were called because a remote host has connected to us. If uip_newdata() is non-zero, we were called because the remote host has sent us new data, and if uip_acked() is non-zero, the remote host has acknowledged the data we previously sent to it. */ if(uip_connected()) { /* Since we've just been connected, the state pointer should be NULL and we need to allocate a new state object. If we have run out of memory for state objects, we'll have to abort the connection and return. */ if(hs == NULL) { hs = alloc_state(); if(hs == NULL) { uip_close(); return; } dispatcher_markconn(uip_conn, (void *)hs); } /* Since we have just been connected with the remote host, we reset the state for this connection. The ->count variable contains the amount of data that is yet to be sent to the remote host, and the ->state is set to HTTP_NOGET to signal that we haven't received any HTTP GET request for this connection yet. */ hs->state = HTTP_NOGET; hs->count = 0; hs->poll = 0; } else if(uip_closed() || uip_aborted()) { if(hs != NULL) { dealloc_state(hs); } return; } else if(uip_poll()) { /* If we are polled ten times, we abort the connection. This is because we don't want connections lingering indefinately in the system. */ if(hs != NULL) { if(hs->state == HTTP_DEALLOCATED) { uip_abort(); } else if(hs->poll++ >= 100) { uip_abort(); dealloc_state(hs); } } return; } if(uip_newdata() && hs->state == HTTP_NOGET) { hs->poll = 0; /* This is the first data we receive, and it should contain a GET. */ /* Check for GET. */ if(uip_appdata[0] != ISO_G || uip_appdata[1] != ISO_E || uip_appdata[2] != ISO_T || uip_appdata[3] != ISO_space) { /* If it isn't a GET, we abort the connection. */ uip_abort(); dealloc_state(hs); return; } beep(); /* Find the file we are looking for. */ for(i = 4; i < 40; ++i) { if(uip_appdata[i] == ISO_space || uip_appdata[i] == ISO_cr || uip_appdata[i] == ISO_nl) { uip_appdata[i] = 0; break; } } PRINT("request for file "); PRINTLN(&uip_appdata[4]); webserver_log_file(uip_conn->ripaddr, &uip_appdata[4]); /* Check for a request for "/". */ if(uip_appdata[4] == ISO_slash && uip_appdata[5] == 0) { httpd_fs_open(file_index_html.name, &fsfile); } else { if(!httpd_fs_open((const char *)&uip_appdata[4], &fsfile)) { PRINTLN("couldn't open file"); httpd_fs_open(file_404_html.name, &fsfile); } } if(uip_appdata[4] == ISO_slash && uip_appdata[5] == ISO_c && uip_appdata[6] == ISO_g && uip_appdata[7] == ISO_i && uip_appdata[8] == ISO_slash) { /* If the request is for a file that starts with "/cgi/", we prepare for invoking a script. */ hs->script = fsfile.data; next_scriptstate(); } else { hs->script = NULL; /* The web server is now no longer in the HTTP_NOGET state, but in the HTTP_FILE state since is has now got the GET from the client and will start transmitting the file. */ hs->state = HTTP_FILE; /* Point the file pointers in the connection state to point to the first byte of the file. */ hs->dataptr = fsfile.data; hs->count = fsfile.len; } } if(hs->state != HTTP_FUNC) { /* Check if the client (remote end) has acknowledged any data that we've previously sent. If so, we move the file pointer further into the file and send back more data. If we are out of data to send, we close the connection. */ if(uip_acked()) { hs->poll = 0; if(hs->count >= uip_mss()) { hs->count -= uip_mss(); hs->dataptr += uip_mss(); } else { hs->count = 0; } if(hs->count == 0) { if(hs->script != NULL) { next_scriptline(); next_scriptstate(); } else { uip_close(); dealloc_state(hs); } } } } if(hs->state == HTTP_FUNC) { /* Call the CGI function. */ #if 1 if(httpd_cgitab[hs->script[2] - ISO_a]()) { /* If the function returns non-zero, we jump to the next line in the script. */ next_scriptline(); next_scriptstate(); } #endif } if(hs->state != HTTP_FUNC && !uip_poll()) { hs->poll = 0; /* Send a piece of data, but not more than the MSS of the connection. */ uip_send(hs->dataptr, hs->count > uip_mss()? uip_mss(): hs->count); } /* Finally, return to uIP. Our outgoing packet will soon be on its way... */ }