SSブログ

「オープンソースハードウェアセミナーVol1」レポート Arduino WEBサーバー リクエストの解析をちょっと始める [ATmarquino Arduino]

※なんかイマイチなんで、近日中に書き直すつもり。

Img_1427.jpg表示している内容は変わらないのだけれど、処理が随分機能アップしています、、、嘘!する予定。

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 */
/****************************************************************/


Arduinoモニタープログラム参加中
電子部品・半導体の通販サイト - チップワンストップ




マスタリングTCP/IP 入門編 第4版

マスタリングTCP/IP 入門編 第4版

  • 作者: 竹下 隆史
  • 出版社/メーカー: オーム社
  • 発売日: 2007/02/24
  • メディア: 大型本



ネットワークはなぜつながるのか 第2版 知っておきたいTCP/IP、LAN、光ファイバの基礎知識

ネットワークはなぜつながるのか 第2版 知っておきたいTCP/IP、LAN、光ファイバの基礎知識

  • 作者: 戸根 勤
  • 出版社/メーカー: 日経BP社
  • 発売日: 2007/04/12
  • メディア: 単行本(ソフトカバー)



詳解TCP/IP〈Vol.2〉実装

詳解TCP/IP〈Vol.2〉実装

  • 作者: ゲリー・R. ライト
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2002/12
  • メディア: 単行本



nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。