📄 httpd.c
字号:
/*,-----------------------------------------------------------------------------------------.| net/httpd|-----------------------------------------------------------------------------------------| this file implements a very basic http server| - support for HTTP POST | - support for http basic auuth (all /adm/.. file acces must be authorized)|| KNOWN PROBLEMS:| - somehow quick&dirty implementation ! sorry for that ;)| - uses some dirty hacks (content length detection etc)| - very big routines without function calls for memory/flash/speed reasons| - not really documented :-\| - http authorization does not work if browser request is split into two packets ! (-> always not authorized)| - httpd_add_prog* only use 16bit as data offset ! -> biggest filesize in avr flash is 65k!!!|| Author : {{removed according to contest rules}}| -> circuitcellar.com avr design contest 2006| -> Entry #AT2616||-----------------------------------------------------------------------------------------| License:| 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 2 of the License, or (at your option) any later| version.| This program is distributed in the hope that it will be useful, but|| WITHOUT ANY WARRANTY;|| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR| PURPOSE. See the GNU General Public License for more details.|| You should have received a copy of the GNU General Public License along with| this program; if not, write to the Free Software Foundation, Inc., 51| Franklin St, Fifth Floor, Boston, MA 02110, USA|| http://www.gnu.de/gpl-ger.html`-----------------------------------------------------------------------------------------*/#include "httpd.h"//ACTIVATE DEBUG by editing this file:#include "debug.h"///FIXME: include the .c file here !/// without this sizeof() does not work !! -> is there another way to do this ?!#include "httpd_data.c"struct httpd_conn_struct { unsigned char state; unsigned char substate; unsigned int file_id; unsigned long seq_offset; unsigned int data_ptr; unsigned long data_position;};struct httpd_conn_struct httpd_conn[TCP_SOCKET_COUNT];//initialise connection tablevoid httpd_init(void){ for(unsigned char c=0; c<TCP_SOCKET_COUNT; c++){ httpd_cleanup_conn(c); }}//initialise/cleanup http connvoid httpd_cleanup_conn(unsigned char i){ if (i<TCP_SOCKET_COUNT){ httpd_conn[i].state = HTTPD_STATE_IDLE; httpd_conn[i].data_position = 0; }}//return: how many data bytes should be transferred ?unsigned int httpd_data_in(unsigned char *buffer, unsigned int datapos, unsigned int datalen, unsigned char socketnum, unsigned char *appstate){ unsigned int pos; unsigned char file_name[8+6+1]; unsigned char file_ext[3+1]; unsigned char f; unsigned int ret; unsigned long offset; unsigned char authorized; pos = 0; #if HTTPD_DEBUG2 softuart_puts_progmem("HTTP: SEQ-SEQ_OFFSET_DATA = "); softuart_put_uint16((tcp_sockets[socketnum].seq-httpd_conn[socketnum].seq_offset)&0xFFFF); softuart_puts_progmem("\r\n"); #endif //initialise filename: for (f=0; f<8+6+1; f++) file_name[f] = 0; for (f=0; f<3+1; f++) file_ext[f] = 0; switch(httpd_conn[socketnum].state){ case(HTTPD_STATE_IDLE): //case(HTTPD_STATE_IDLE_r): //case(HTTPD_STATE_IDLE_rn): //case(HTTPD_STATE_IDLE_rnr): //case(HTTPD_STATE_IDLE_rnrn): //new request, scan for GET/POST: if ((buffer[datapos + 0] == 'G') && (buffer[datapos + 1] == 'E') && (buffer[datapos + 2] == 'T')){ //get request ! pos = datapos + 3; f = 0; //find start of requested url while(buffer[pos] == ' ') pos++; while((buffer[pos] != ' ') && (buffer[pos] != '\r') && (buffer[pos] != '\n') && (buffer[pos] != '?') && (pos<datapos+datalen)){ //read requested file, //read filename: file_name[f] = buffer[pos]; //read file extension: /*if (!((file_ext[2] == ' ') || (file_ext[2] == '?'))){ file_ext[0] = file_ext[1]; file_ext[1] = file_ext[2]; file_ext[2] = buffer[pos]; }*/ if (buffer[pos] == '.'){ file_ext[0] = buffer[pos+1]; file_ext[1] = buffer[pos+2]; file_ext[2] = buffer[pos+3]; file_name[f] = 0; break; } if (file_name[f] == '.') file_name[f] = 0; if (f<8+6) f++; //remove first / if (file_name[0] == '/') f=0; pos++; } //if (file_name[f]=='.') // file_name[f] = 0; #if HTTPD_DEBUG softuart_puts_progmem("HTTP: GET <"); for(f=0;f<8+6 && file_name[f];f++) softuart_putc(file_name[f]); softuart_putc('.'); for(f=0;f<3 && file_ext[f];f++) softuart_putc(file_ext[f]); softuart_puts_progmem(">.\r\n"); #endif //set file id: if (file_name[0] == '/' || string_compare_progmem("index", file_name)){ ///show index httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_INDEX; file_ext[0] = 'h'; //->html }else if ( string_compare_progmem("site/cam", file_name)){ ///show webcam pic httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_SITE_CAM; }else if ( string_compare_progmem("site/temp", file_name)){ ///show templog site httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_SITE_TEMP; }else if ( string_compare_progmem("site/io", file_name)){ ///show io site httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_SITE_IO; }else if ( string_compare_progmem("site/ficon", file_name)){ ///show file icon httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_SITE_FILE_ICON_PIC; }else if ( string_compare_progmem("graph_0", file_name)){ ///show tempgraph (use eeprom data) httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_GRAPH0; }else if ( string_compare_progmem("fs/ls", file_name)){ ///show dataflash file list httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_FS_LS; }else if ( string_compare_progmem("cam/pic", file_name)){ ///show webcam image httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_CAM_PIC; }else if ( string_compare_progmem("cam/busy", file_name)){ ///show webcam busy image httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_CAM_BUSY; }else if ( string_compare_progmem("site/servo", file_name)){ ///show servo page httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_SERVO_OK; }else if ( string_compare_progmem_noeof("servo_", file_name)){ ///show/set servo pos //parse number & set servopos (use uint16 parser) //if you want to show servopos without moving use servo_999.bmp for example if (string_buffer_to_uint16(&file_name[6])<256) servo_set_pos(string_buffer_to_uint16(&file_name[6])&0xFF); httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_SERVO_POS; }else if ( string_compare_progmem_noeof("set/", file_name)){ ///show port image if(file_name[7] == '1'){ httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_SET_IO_1_PIC; port_set_portbit(file_name[4], file_name[5], 1); }else{ httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_SET_IO_0_PIC; port_set_portbit(file_name[4], file_name[5], 0); } //deprecated //}else if ( string_compare_progmem_noeof("fs/f", file_name)){ // ///show dataflash file with id given (fs/f1234 -> file 1234 !): // httpd_conn[socketnum].file_id = 0xFF + string_buffer_to_uint16(&file_name[4]); }else if ( string_compare_progmem_noeof("fs/", file_name)){ ///try to find dataflash file with the given name: httpd_conn[socketnum].file_id = 0xFF + filesystem_search_file(&file_name[3], &file_ext[0]); httpd_conn[socketnum].data_ptr = 0; if (httpd_conn[socketnum].file_id == 0xFF) httpd_conn[socketnum].file_id = HTTPD_STATE_IDLE; ///no file found ! }else if ( string_compare_progmem("adm/up", file_name)){ ///show upload form httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_UP; }else if ( string_compare_progmem_noeof("adm/rm/", file_name)){ ///try to find dataflash file with the given name: httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_REMOVED; }else if ( string_compare_progmem("adm/mkfs", file_name)){ ///format filesystem question httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_MKFS; }else if ( string_compare_progmem("adm/mkfs2", file_name)){ ///format filesystem exec! httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_MKFS2; }else{ ///FILE not found -> 404 err httpd_conn[socketnum].file_id = HTTPD_STATE_IDLE; } //initialise substate httpd_conn[socketnum].substate = HTTPD_SUBSTATE_NONE; }else if ((buffer[datapos + 0] == 'P') && (buffer[datapos + 1] == 'O') && (buffer[datapos + 2] == 'S') && (buffer[datapos + 3] == 'T')){ //QUICK HACK (TEST!) httpd_conn[socketnum].file_id = HTTPD_STATE_FILE_POST; string_progmem_to_buffer(PSTR("adm/"), file_name,4); //initialise substate httpd_conn[socketnum].substate = HTTPD_SUBSTATE_NONE; } //find the content length! //use a quick & dirty method for this !!! //-> we search for *th: <number> // (instead of content-length:) // // we do this because to minimize the following problem: // clen detection DOES NOT work when the header is // split into multiple packets & the packetborder // is anywhere between th: <number> !! FIXME! if (httpd_conn[socketnum].file_id == 0xFE){ pos = datapos; //pos+4 because len("th: ") is 4 (fixme: number might be outside packetlen!) while (pos+4<datapos+datalen){ if (string_compare_progmem_noeof("th: ", &buffer[pos])){ //next is the number ! //parse it ! httpd_conn[socketnum].data_position = string_buffer_to_uint32(&buffer[pos+4]); break; } pos++; } } ///search for authorization key authorized = 0; if (string_compare_progmem_noeof("adm/", file_name)){ //accessing admin zone, search for auth! #if HTTPD_DEBUG_AUTH softuart_puts_progmem("HTTPD: auth required! ["); #endif pos = datapos; while(pos<datapos+datalen){ //speedup, check first letter if (buffer[pos] == 'A'){ //if match, call whole function match if (string_compare_progmem_noeof("Authorization: Basic ", &buffer[pos])){ //got it ! now buf[pos+21]-... has auth string! unsigned char len; unsigned char *pwbuff = &buffer[pos+21]; //maximum pw len 100 for(len=0; len < 100; len++){ //check buf < '0' is ok because of base64... \r\n & space are smaller ;) if (pwbuff[len]<'0') break; #if HTTPD_DEBUG_AUTH softuart_putc(pwbuff[len]); #endif } //len--; //base64 decode, after this the decoded string is in buffer[pos+21]... base64_decode(&pwbuff[0], len); #if HTTPD_DEBUG_AUTH softuart_puts_progmem("], decoded ["); for(len=0; len < 100; len++){ if (pwbuff[len]==0) break; softuart_putc(pwbuff[len]); } softuart_puts_progmem("] auth? "); #endif if (string_compare_progmem(HTTPD_ADMIN_AUTH_LOGIN":"HTTPD_ADMIN_AUTH_PASS, &pwbuff[0])){ //auth passed !! authorized = 1; } #if HTTPD_DEBUG_AUTH softuart_put_uint8(authorized); softuart_putnewline(); #endif break; } } pos++; } //check if there was a file remove request if (authorized && (httpd_conn[socketnum].file_id == HTTPD_STATE_FILE_REMOVED)){ httpd_conn[socketnum].file_id = 0xFF + string_buffer_to_uint16(&file_name[7]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -