注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

老和山小和尚

敬天爱人

 
 
 

日志

 
 
 
 

Ragel for http response  

2010-03-26 16:07:43|  分类: 协议研究 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
原来我写了一篇:Ragel for http example (Mongrel HTTP 1/1)用于解析HTTP请求。今天我尝试改写了一下原有的脚本,用以解析 HTTP回复。

1、所需文件:

http11_response_common.rl:HTTP 回复的正则定义
%%{
  
  machine http_response_common;
 
#### HTTP PROTOCOL GRAMMAR
# line endings
  CRLF = "\r\n";
 
# character types
  CTL = (cntrl | 127);
  tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
 
# elements
  token = (ascii -- (CTL | tspecials));
 
  Reason_Phrase = ( ascii -- ("\r" | "\n") )+ >mark %reason_phrase;
 
  Status_Code = ( digit+ ) >mark %status_code ;
 
  http_number = ( digit+ "." digit+ ) ;
  HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
 
  Response_Line = ( HTTP_Version " " Status_Code " " Reason_Phrase CRLF ) ;
 
  field_name = ( token -- ":" )+ >start_field %write_field;
 
  field_value = any* >start_value %write_value;
 
  message_header = field_name ":" " "* field_value :> CRLF;
 
  Response = Response_Line ( message_header )* ( CRLF @done );
 
main := Response;
 
}%%
http11_response.rl :主要的动作处理过程
#include "http11_response.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
 
 
#define LEN(AT, FPC) (FPC - buffer - parser->AT)
#define MARK(M,FPC) (parser->M = (FPC) - buffer)
#define PTR_TO(F) (buffer + parser->F)
 
/** Machine **/
 
%%{
  
  machine http_parser;
 
  action mark {MARK(mark, fpc); }
 
  action start_field { MARK(field_start, fpc); }
  action write_field {
    parser->field_len = LEN(field_start, fpc);
  }
 
  action start_value { MARK(mark, fpc); }
 
  action write_value {
    if(parser->http_field != NULL) {
      parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
    }
  }
 
  action http_version {
    if(parser->http_version != NULL)
      parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
  }
 
  action status_code {
    if(parser->status_code != NULL)
      parser->status_code(parser->data, PTR_TO(mark), LEN(mark,fpc));
  }
 
  action reason_phrase {
    if(parser->reason_phrase != NULL)
      parser->reason_phrase(parser->data, PTR_TO(mark), LEN(mark,fpc));
  }
 
  action done {
    parser->body_start = fpc - buffer + 1;
    if(parser->header_done != NULL)
      parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
    fbreak;
  }
 
  include http_response_common "http11_response_common.rl";
 
}%%
 
/** Data **/
%% write data;
 
int http_parser_init(http_parser *parser) {
  int cs = 0;
  %% write init;
  parser->cs = cs;
  parser->body_start = 0;
  parser->content_len = 0;
  parser->mark = 0;
  parser->nread = 0;
  parser->field_len = 0;
  parser->field_start = 0;
 
  return(1);
}
 
 
/** exec **/
size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
  const char *p, *pe;
  int cs = parser->cs;
 
  assert(off <= len && "offset past end of buffer");
 
  p = buffer+off;
  pe = buffer+len;
 
  assert(pe - p == len - off && "pointers aren't same distance");
 
  %% write exec;
 
  if (!http_parser_has_error(parser))
    parser->cs = cs;
  parser->nread += p - (buffer + off);
 
  assert(p <= pe && "buffer overflow after parsing execute");
  assert(parser->nread <= len && "nread longer than length");
  assert(parser->body_start <= len && "body starts after buffer end");
  assert(parser->mark < len && "mark is after buffer end");
  assert(parser->field_len <= len && "field has length longer than whole buffer");
  assert(parser->field_start < len && "field starts after buffer end");
 
  return(parser->nread);
}
 
int http_parser_finish(http_parser *parser)
{
  if (http_parser_has_error(parser) ) {
    return -1;
  } else if (http_parser_is_finished(parser) ) {
    return 1;
  } else {
    return 0;
  }
}
 
int http_parser_has_error(http_parser *parser) {
  return parser->cs == http_parser_error;
}
 
int http_parser_is_finished(http_parser *parser) {
  return parser->cs >= http_parser_first_final;
}


http11_response.h :头部定义

#ifndef http11_parser_h
#define http11_parser_h
 
#include <sys/types.h>
 
#if defined(_WIN32)
#include <stddef.h>
#endif
 
typedef void (*element_cb)(void *data, const char *at, size_t length);
typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
 
typedef struct http_parser {
  int cs;
  size_t body_start;
  int content_len;
  size_t nread;
  size_t mark;
  size_t field_start;
  size_t field_len;
  size_t query_start;
 
  void *data;
 
  field_cb http_field;
 
  element_cb http_version;
  element_cb status_code;
  element_cb reason_phrase;
  element_cb header_done;
  
} http_parser;
 
int http_parser_init(http_parser *parser);
int http_parser_finish(http_parser *parser);
size_t http_parser_execute(http_parser *parser, const char *data, size_t len, size_t off);
int http_parser_has_error(http_parser *parser);
int http_parser_is_finished(http_parser *parser);
 
#define http_parser_nread(parser) (parser)->nread
 
#endif
 

ragel_http_client.c : 一般用户自定义的处理过程

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "http11_response.h"
#include <ctype.h>
 
#define BUFF_LEN 4096
 
void http_field(void *data, const char *field,
        size_t flen, const char *value, size_t vlen)
{
    char buff[BUFF_LEN] = {0};
 
    strncpy(buff, field, flen);
    strcat(buff, ": ");
    strncat(buff, value, vlen);
 
    printf("HEADER: \"%s\"\n", buff);
}
 
void http_version(void *data, const char *at, size_t length)
{
    printf("VERSION: \"%.*s\"\n", length, at);
}
 
void status_code(void *data, const char *at, size_t length)
{
    printf("STATUS_CODE: \"%.*s\"\n", length, at);
}
 
void reason_phrase(void *data, const char *at, size_t length)
{
    printf("REASON_PHRASE: \"%.*s\"\n", length, at);
}
 
void header_done(void *data, const char *at, size_t length)
{
    printf("HEADER_DONE.\n");
}
 
void parser_init(http_parser *hp)
{
    hp->http_field = http_field;
    hp->http_version = http_version;
    hp->status_code = status_code;
    hp->reason_phrase = reason_phrase;
    hp->header_done = header_done;
    http_parser_init(hp);
}
//完整的包解析

int main1 ()
{
    char *data = "HTTP/1.0 200 OK\r\n"
        "Server: nginx\r\n"
        "Date: Fri, 26 Mar 2010 03:39:03 GMT\r\n"
        "Content-Type: text/html; charset=GBK\r\n"
        "Vary: Accept-Encoding\r\n"
        "Expires: Fri, 26 Mar 2010 03:40:23 GMT\r\n"
        "Cache-Control: max-age=80\r\n"
        "Vary: User-Agent\r\n"
        "Vary: Accept\r\n"
        "X-Cache: MISS from cache.163.com\r\n"
        "Connection: close\r\n"
        "\r\n"
        "I am the body"
        ;
    size_t dlen;
    http_parser parser, *hp;
 
    hp = &parser;
    dlen = strlen(data);
 
    parser_init(hp);
 
    http_parser_execute(hp, data, dlen, 0);
 
    return 0;
}

  //异步处理的包解析

int main ()
{
    char *data = "HTTP/1.0 200 OK\r\n"
        "Server: nginx\r\n"
        "Date: Fri, 26 Mar 2010 03:39:03 GMT\r\n"
        "Content-Type: text/html; charset=GBK\r\n"
        "Vary: Accept-Encoding\r\n"
        "Expires: Fri, 26 Mar 2010 03:40:23 GMT\r\n"
        "Cache-Control: max-age=80\r\n"
        "Vary: User-Agent\r\n"
        "Vary: Accept\r\n"
        "X-Cache: MISS from cache.163.com\r\n"
        "Connection: close\r\n"
        "\r\n"
        "I am the body"
        ;
 
 
    size_t dlen, dlen1;
    http_parser parser, *hp;
    int i;
 
    hp = &parser;
    dlen = strlen(data);
 
    for (i = 1;i < dlen;i++) {
        printf("\n\nblock point: %d\n", i);
        parser_init(hp);
        dlen1 = http_parser_execute(hp, data, i, 0);
        dlen1 = http_parser_execute(hp, data, dlen, dlen1);
        printf("BODY: \"%s\"\n", data + hp->body_start);
    }
 
    return 0;
}


  评论这张
 
阅读(1897)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017