「オープンソースハードウェアセミナーVol1」レポート Arduino WEBサーバー リクエストの解析をちょっと始める [ATmarquino Arduino]
※なんかイマイチなんで、近日中に書き直すつもり。
表示している内容は変わらないのだけれど、処理が随分機能アップしています、、、嘘!する予定。
GET Methodの解析、uriの解析、Mimeタイプの解析はもう疲れて適当に終了。
表示している内容は変わらないのだけれど、処理が随分機能アップしています、、、嘘!する予定。
GET Methodの解析、uriの解析、Mimeタイプの解析はもう疲れて適当に終了。
/****************************************************************/ /* Web Serverで色々いじってみる計画 */ /* Copyright (c) せくすぃ部長 since 2009/06/13 */ /****************************************************************/ /****************************************************************/ /* file include */ /****************************************************************/ #include <Ethernet.h> #include <ctype.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <avr/pgmspace.h> /****************************************************************/ /* 色々定義 */ /****************************************************************/ #define LINE_STRING_SIZE 128 enum HTTP_METHOD_TYPE { METHOD_TYPE_IS_GET = 1, METHOD_TYPE_IS_HEAD, METHOD_TYPE_IS_PUT, METHOD_TYPE_IS_POST, METHOD_TYPE_IS_DELETE, METHOD_TYPE_IS_LINK, METHOD_TYPE_IS_UNLINK, }; enum HTTP_ADD_TYPE { AddHandler, /*ハンドラ*/ AddType_TXT, /*テキスト*/ AddType_IMAGE, /*イメージ*/ AddType_APPLI, /*アプリケーション*/ AddType_AUDIO, /*audio*/ AddType_VIDEO, /*video*/ }; /****************************************************************/ /* 大域変数領域 */ /****************************************************************/ char *line; char meth[10],uri[30],ver[20]; long access_count; const byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; const byte ip[] = { 192, 168, 1, 177 }; const byte gateway[] = { 192, 168, 1, 1 }; /****************************************************************/ /* サーバーレスポンスの固定メッセージ */ /****************************************************************/ const char PROGMEM http_head[] = "HTTP/1.0 200 OK\r\n" \ "Server: Arduino with Ether Shield/ ver.0.2\r\n" \ "Content-Type: text/html; charset=UTF-8\r\n\r\n" \ "<html lang=\"ja\"><head>\r\n" \ "<meta HTTP-EQUIV=\"Content-type\" CONTENT=\"text/html; charset=UTF-8\">\r\n" \ "<title>Arduino WEB Server 0.1</title></head>\r\n" \ "<body bgcolor=\"#ccffcc\">\r\n"; const char PROGMEM thanks[] = "<h3>designed by hamayan</h3>\r\n" \ "アクセス有難うございます。このページはArduino+Ether Shieldで表示しています。<br>\r\n" \ "現在はリクエストのパーサーを作成しています。<br>\r\n"; const char PROGMEM links[] = "hamayan blog <a href=\"http://hamayan.blog.so-net.ne.jp/\">http://hamayan.blog.so-net.ne.jp/</a><br>\r\n" \ "chip 1 stop <a href=\"http://www.chip1stop.com/\">http://www.chip1stop.com/</a><br>\r\n" \ "オープンソースハードウェアセミナーのページ <a href=\"http://www.chip1stop.com/knowledge/Arduino/\">http://www.chip1stop.com/knowledge/Arduino/</a><br>\r\n" \ "Make:Japan <a href=\"http://jp.makezine.com/blog/\">http://jp.makezine.com/blog/</a><br><br>\r\n"; const char PROGMEM banner_01[] = "<p><a href=\"http://www.chip1stop.com/knowledge/Arduino/\">" \ "<img src=\"http://www.chip1stop.com/img/link_Arduino.gif\" width=\"468\" height=\"60\" alt=\"Arduinoモニタープログラム参加中\" /></a><br>" \ "<a href=\"http://www.chip1stop.com/\" title=\"電子部品・半導体の通販サイト - チップワンストップ\">電子部品・半導体の通販サイト - チップワンストップ</a></p><br><br>\r\n"; const char PROGMEM http_foot[] = "</body></html>\r\n\r\n"; const char PROGMEM img_src[] = "<p><img src=\"./image2.jpg\" width=\"200\" height=\"140\" align=\"center\"></p><br><br>\r\n"; const char PROGMEM jpeg_head[] = "HTTP/1.0 200 OK\r\n" \ "Server: Arduino with Ether Shield/ ver.0.2\r\n" \ "Content-Type: image/JPEG\r\n\r\n"; const char PROGMEM HtmlRes400[] = { "HTTP/1.0 400 Bad Request\r\n" \ "Server: Arduino with Ether Shield/ ver.0.2\r\n" \ "Content-Type: text/html; charset=UTF-8\r\n\r\n" \ "<html lang=\"ja\"><head><title>400 Bad Request</title></head>\r\n" \ "<h1>Bad Request</h1>\r\n" \ "</body></html>\r\n\r\n" }; const char PROGMEM HtmlRes404[] = { "HTTP/1.0 404 Not Found\r\n" \ "Server: Arduino with Ether Shield/ ver.0.2\r\n" \ "Content-Type: text/html; charset=UTF-8\r\n\r\n" \ "<html lang=\"ja\"><head><title>404 Not Found</title></head>\r\n" \ "<h1>Not Found</h1>\r\n" \ "</body></html>\r\n\r\n" }; const char PROGMEM HtmlRes405[] = { "HTTP/1.0 405 Method Not Allowed\r\n" \ "Server: Arduino with Ether Shield/ ver.0.2\r\n" \ "Content-Type: text/html; charset=UTF-8\r\n\r\n" \ "<html lang=\"ja\"><head><title>405 Method Not Allowed</title></head>\r\n" \ "<h1>Method Not Allowed</h1>\r\n" \ "</body></html>\r\n\r\n" }; Server server( 8888 ); /****************************************************************/ /* setup */ /****************************************************************/ void setup() { Ethernet.begin( (uint8_t *)mac, (uint8_t *)ip, (uint8_t *)gateway ); server.begin(); Serial.begin( 38400 ); line = (char *)malloc( LINE_STRING_SIZE ); } /****************************************************************/ /* loop */ /****************************************************************/ void loop() { Client client = server.available(); if( client ) { while( client.connected() ) { char *dst = HTTPGets( client, line, LINE_STRING_SIZE ); char *argv[ 10 ]; int div_num = split( dst, argv, sizeof(argv) / sizeof(argv[0]) ); /*文字列分割*/ strncpy( meth, argv[ 0 ], sizeof(meth) ); strncpy( uri, argv[ 1 ], sizeof(uri) ); strncpy( ver, argv[ 2 ], sizeof(ver) ); break; } while( client.connected() ) { char *dst = HTTPGets( client, line, LINE_STRING_SIZE ); if( dst != NULL && *dst == '\0' ) /*改行のみの行を検出*/ { server_response( client, meth, uri ); break; } } // delay( 1 ); client.stop(); } } /****************************************************************/ /* サーバー側の応答処理 */ /****************************************************************/ void server_response( Client client, char *method, char *uri ) { int meth; static const struct COMMAND_LIST { void ( PROGMEM *fn )( Client client, char *uri ); char PROGMEM *meth_name; } list[] = { { Method_GET, "GET" }, { Method_HEAD, "HEAD" }, { Method_PUT, "PUT" }, { Method_POST, "POST" }, { Method_DELETE, "DELETE" }, { Method_LINK, "LINK" }, { Method_UNLINK, "UNLINK" }, }; for( meth = 0; meth < sizeof( list ) / sizeof( list[0] ); meth++ ) { /*メソッド文字列の比較を行い、該当するメソッドが見つかれば実行する*/ if( strncmp( method, list[ meth ].meth_name, strlen( list[ meth ].meth_name ) ) == 0 ) { list[ meth ].fn( client, uri ); break; } } if( meth == sizeof( list ) / sizeof( list[0] ) ) { Bad_Request( client ); } } /****************************************************************/ /* METHOD GET */ /****************************************************************/ static void Method_GET( Client client, char *uri ) { int req; static const struct URL_LIST { char PROGMEM *name; int PROGMEM type; void PROGMEM *property; } list[] = { {"/", AddType_TXT, 0}, {"/index.html", AddType_TXT, 0}, {"/index.htm", AddType_TXT, 0}, }; for( req = 0; req < sizeof( list ) / sizeof( list[0] ); req++ ) { /*uriの比較を行い、該当するuriが見つかれば実行する*/ if( strcmp( uri, list[ req ].name ) == 0 ) { break; } } if( req == sizeof( list ) / sizeof( list[0] ) ) { /*要求されたuriが見付からなかった時*/ client.write_P( HtmlRes404, sizeof( HtmlRes404 ) - 1 ); return; } switch( list[ req ].type ) { case AddType_TXT : Response_Handler( client, uri ); break; case AddHandler : case AddType_IMAGE : case AddType_APPLI : case AddType_AUDIO : case AddType_VIDEO : default : client.write_P( HtmlRes404, sizeof( HtmlRes404 ) - 1 ); break; } } /****************************************************************/ /* 応答メッセージの出力 */ /****************************************************************/ static void Response_Handler( Client client, char *uri ) { if( 1 ) /*今のところ拡張子まで判定していないので、全部同じ動きをさせる*/ { //httpヘッダーの返信 client.write_P( http_head, sizeof( http_head ) - 1 ); //サンキューメッセージ client.write_P( thanks, sizeof( thanks ) - 1 ); //リンク client.write_P( (const uint8_t *)links, sizeof( links ) - 1 ); //Arduinoバージョン sprintf( line, "Arduino ver=%d <br>\r\n", ARDUINO ); client.write( line ); //アクセスカウント sprintf( line, "COUNT=%d <br>\r\n", ++access_count ); client.write( line ); //バナー client.write_P( (const uint8_t *)banner_01, sizeof( banner_01 ) - 1 ); //Footer client.write_P( (const uint8_t *)http_foot, sizeof( http_foot ) - 1 ); } } /****************************************************************/ /* METHOD HEAD */ /****************************************************************/ static void Method_HEAD( Client client, char *uri ) { /*現在サポートしていないので、許可されていないメソッドとして返信*/ client.write_P( HtmlRes405, sizeof( HtmlRes405 ) - 1 ); } /****************************************************************/ /* METHOD PUT */ /****************************************************************/ static void Method_PUT( Client client, char *uri ) { /*現在サポートしていないので、許可されていないメソッドとして返信*/ client.write_P( HtmlRes405, sizeof( HtmlRes405 ) - 1 ); } /****************************************************************/ /* METHOD POST */ /****************************************************************/ static void Method_POST( Client client, char *uri ) { /*現在サポートしていないので、許可されていないメソッドとして返信*/ client.write_P( HtmlRes405, sizeof( HtmlRes405 ) - 1 ); } /****************************************************************/ /* METHOD DELETE */ /****************************************************************/ static void Method_DELETE( Client client, char *uri ) { /*現在サポートしていないので、許可されていないメソッドとして返信*/ client.write_P( HtmlRes405, sizeof( HtmlRes405 ) - 1 ); } /****************************************************************/ /* METHOD LINK */ /****************************************************************/ static void Method_LINK( Client client, char *uri ) { /*現在サポートしていないので、許可されていないメソッドとして返信*/ client.write_P( HtmlRes405, sizeof( HtmlRes405 ) - 1 ); } /****************************************************************/ /* METHOD UNLINK */ /****************************************************************/ static void Method_UNLINK( Client client, char *uri ) { /*現在サポートしていないので、許可されていないメソッドとして返信*/ client.write_P( HtmlRes405, sizeof( HtmlRes405 ) - 1 ); } /****************************************************************/ /* BAD REQUEST */ /****************************************************************/ static void Bad_Request( Client client ) { client.write_P( HtmlRes400, sizeof( HtmlRes400 ) - 1 ); } /****************************************************************/ /* 一行取得 */ /* HTTPプロトコルでは行末はCR、LFであると言う前提がある */ /****************************************************************/ static char *HTTPGets( Client client, char *dst, int size ) { int loop; char c,*ptr,*limit; ptr = dst; limit = dst + size; for( loop = 10; loop > 0; loop-- ) { if( ptr == limit ) return (char *)0; /*上限の確認*/ if( client.available() ) { loop = 10; /*タイムアウト延長*/ c = client.read(); /*一文字取得*/ if( c == '\r' ) /*CRはNULLに変換*/ { *ptr++ = '\0'; } else if( c == '\n' ) /*LFは終端文字*/ { *ptr = '\0'; return dst; } else /*文字の取得*/ { *ptr++ = c; } } else { delay( 100 ); /*残りのデータが遅れて来る可能性があるので、ここで待ちを入れる*/ } } return (char *)0; } /****************************************************************/ /* 文字列分割ユーティリティ */ /****************************************************************/ static int split( char *str , char *argv[], int sz ) { int argc = 0; while( *str != '\0' && argc < sz ) { if( isgraph( *str ) != 0 ) { argv[ argc++ ] = str; while( *str != '\0' && isgraph( *str ) != 0 ) str++; } else *str++ = '\0'; } return argc; } /****************************************************************/ /* end of file */ /* Copyright (c) せくすぃ部長 since 2009/06/13 */ /****************************************************************/
ネットワークはなぜつながるのか 第2版 知っておきたいTCP/IP、LAN、光ファイバの基礎知識
- 作者: 戸根 勤
- 出版社/メーカー: 日経BP社
- 発売日: 2007/04/12
- メディア: 単行本(ソフトカバー)
2009-06-14 00:53
nice!(0)
コメント(0)
トラックバック(0)
コメント 0