最近公司要上CDN网络,做一些视频的缓存,为了用squid进行视频缓存,必须要让它实现拖动功能。     

squid并不是为视频专门设计的缓存软件,所以当缓存视频文件时,并不具有视频拖动功能。

    首先简单了解一下视频为什么能拖动,使用yamdi等视频加帧软件将视频加帧生成metadata信息,里面记录着每一帧对应的文件的以字节为单位的偏移量(offset),播放器获取metadata信息,如果用户拖动了视频的播放进度条,播放器会根据所在帧生成一个url请求,这个请求中包含start=XXX,这个XXX就是这个偏移量,服务器接受到这个请求会从用户指定的偏移量开始读取视频文件,并在前面加上"FLV\x1\x1\0\0\0\x9\0\0\0\x9" 13个字节的一个标记,这样用户在得到服务器的返回值之后能正确的播放视频,完成拖动。

lighttpd 处理视频文件的核心文件是mod_flv_streaming.c

 
  
  1. URIHANDLER_FUNC(mod_flv_streaming_path_handler) { 
  2.     plugin_data *p = p_d; 
  3.     int s_len; 
  4.     size_t k; 
  5.  
  6.     UNUSED(srv); 
  7.  
  8.     if (con->mode != DIRECT) return HANDLER_GO_ON; 
  9.  
  10.     if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON; 
  11.  
  12.     mod_flv_streaming_patch_connection(srv, con, p); 
  13.  
  14.     s_len = con->physical.path->used - 1; 
  15.  
  16.     for (k = 0; k < p->conf.extensions->used; k++) { 
  17.         data_string *ds = (data_string *)p->conf.extensions->data[k]; 
  18.         int ct_len = ds->value->used - 1; 
  19.  
  20.         if (ct_len > s_len) continue
  21.         if (ds->value->used == 0) continue
  22.  
  23.         if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) { 
  24.             data_string *get_param; 
  25.             stat_cache_entry *sce = NULL; 
  26.             buffer *b; 
  27.             int start; 
  28.             char *err = NULL; 
  29.             /* if there is a start=[0-9]+ in the header use it as start, 
  30.              * otherwise send the full file */ 
  31.  
  32.             array_reset(p->get_params); 
  33.             buffer_copy_string_buffer(p->query_str, con->uri.query); 
  34.             split_get_params(p->get_params, p->query_str); 
  35.  
  36.             if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) { 
  37.                 return HANDLER_GO_ON; 
  38.             } 
  39.  
  40.             /* too short */ 
  41.             if (get_param->value->used < 2) return HANDLER_GO_ON; 
  42.  
  43.             /* check if it is a number */ 
  44.             start = strtol(get_param->value->ptr, &err, 10); 
  45.             if (*err != '\0') { 
  46.                 return HANDLER_GO_ON; 
  47.             } 
  48.  
  49.             if (start <= 0) return HANDLER_GO_ON; 
  50.  
  51.             /* check if start is > filesize */ 
  52.             if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { 
  53.                 return HANDLER_GO_ON; 
  54.             } 
  55.  
  56.             if (start > sce->st.st_size) { 
  57.                 return HANDLER_GO_ON; 
  58.             } 
  59.  
  60.             /* we are safe now, let's build a flv header */ 
  61.             b = chunkqueue_get_append_buffer(con->write_queue); 
  62.             buffer_copy_string_len(b, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9")); 
  63.  
  64.             http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start); 
  65.  
  66.             response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv")); 
  67.  
  68.             con->file_finished = 1; 
  69.  
  70.             return HANDLER_FINISHED; 
  71.         } 
  72.     } 
  73.  
  74.     /* not found */ 
  75.     return HANDLER_GO_ON; 

上面是lighttpd处理视频拖动的函数,首先lighttpd获取start的数值,然后发送13个字节的"FLV\x1\x1\0\0\0\x9\0\0\0\x9",然后seek到指定帧的开始处读取文件,生成正确的返回头部content length信息。

回头来看squid,如果要让squid能实现视频的拖动,同样的我们也要完成这项工作,首先我们要让squid能识别用户的包含url中包含的start信息,然后同样的读取指定offset的缓存文件信息,并且加上"FLV\x1\x1\0\0\0\x9\0\0\0\x9"的公共信息,再生成正确的content length信息。但是毕竟squid和lighttpd是不相同的,lighttpd读取的文件都是本地磁盘上的,如果squid本地磁盘上有缓存的话,情况是相似的,但在cache miss的情况下,如何让用户获得更好的体验就不尽相同了,而且squid 要保证对于同一个视频文件磁盘上只出现一个缓存文件,而且这个文件必须是完整的视频文件,不是从某个帧开始的文件。

首先我的设计思路是这样的

 

简单的说明一下上面的处理流程,因为我们的视频是要加密的在每个返回内容的最前面都会有加密信息(这个加密是开发人员修改lighttpd加上去的),这个工作一开始是又lighttpd处理的,加上这样的信息之后squid在设置读取offset的时候会发生问题(因为加密信息是多出来的而且长度是随机的),所以我关闭了lighttpd的加密,然后在hit和miss的情况下都要和"FLV\x1\x1\0\0\0\x9\0\0\0\x9"一起加上加密信息,这个处理对其他人是不适用的。

storeurl rewrite的处理是肯定要有的,因为同一个视频文件因为start值的不同还有一些其他的因素导致url是不相同的,这样请求同一个文件的url也不尽相同,所以我使用了jesred做storeurl rewrite,但是这就会出现一个问题,在cache miss的情况下,一个start不等于0的url请求会记录到磁盘上,但这并不是我们想要的。所以解决方法我想到两个,一个是使用url rewrite (注意这不是storeurl rewrite),将所有start不等于0的url改写成start等于0,这样缓存的肯定是完整的视频文件,但是这会出现一个问题,当服务器端squid并没有将完整的视频抓取到本地的时候,你是不能拖动视频的;所以我想到了另一个办法,当请求的url是miss的时候而且start不等于0的情况下,这个请求不缓存,这样用户在观看视频的时候即使squid的缓存中没有这个文件,他依然可以拖动,但这会牺牲一部分的带宽,当squid将视频抓取到本地之后就是cache hit了,视频访问就会开始快起来。

下面是实现squid拖动的补丁,这个补丁是去掉了加密信息内容的,因为我的测试环境下视频必须加密才能观看,所以我并没有测试下面这个补丁,这是个beta版的补丁,依然有很多需要改进的地方从而进一步完善它的功能。

 
  
  1. --- src/client_side.c   2010-02-14 08:46:25.000000000 +0800 
  2. +++ src/client_side.c   2013-01-15 17:58:18.000000000 +0800 
  3. @@ -106,7 +106,11 @@ 
  4.  #define FAILURE_MODE_TIME 300 
  5.   
  6.  /* Local functions */ 
  7. +static int url_get_start(char *,const char *); 
  8. +static int url_get_startvalue(char *, const char *, intint); 
  9. +static int firstBodyresponse(log_type , squid_off_t ,size_t); 
  10. +static int isTcpMiss(log_type code); 
  11.  static CWCB clientWriteComplete; 
  12.  static CWCB clientWriteBodyComplete; 
  13.  static PF clientReadRequest; 
  14. @@ -168,6 +172,112 @@ 
  15.  static StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags); 
  16.  static inline int clientNatLookup(ConnStateData * conn); 
  17.   
  18. +static int 
  19. +url_get_startvalue(char *uri,const char *key,int end,int urlen){ 
  20. +   char *tmp; 
  21. +   size_t offset=0; 
  22. +   if(uri[end+1] != '='){ 
  23. +       debug(33, 2) ("url_get_startvalue: it is invalid\n"); 
  24. +       return 0; 
  25. +   } 
  26. +   else
  27. +       offset = (size_t)strtol(uri+end+2,&tmp,10); 
  28. +       debug(33, 1) ("url_get_startvalue: start value is %d\n",(int)offset); 
  29. +       return offset; 
  30. +   } 
  31. +} 
  32. +static int 
  33. +url_get_start(char *url, const char *key) { 
  34. +        int find=0; 
  35. +        size_t offset=0; 
  36. +       int a=0; 
  37. +        int b=0; 
  38. +        int urlen=strlen(url); 
  39. +        int keylen=strlen(key); 
  40. +        LOCAL_ARRAY(char, uri, 2048); 
  41. +        strcpy(uri,url); 
  42. +        LOCAL_ARRAY(char, keyword, 40); 
  43. +        strcpy(keyword,key); 
  44. +        while (a<=urlen-1){ 
  45. +           if (uri[a]==keyword[b]){ 
  46. +               if(b==keylen-1){ 
  47. +                   debug(33, 2) ("url_get_start: find start,it starts at %d bit of url\n",a-3); 
  48. +                   find=1; 
  49. +                   offset=url_get_startvalue(uri,key,a,urlen); 
  50. +                   return offset; 
  51. +                   break
  52. +               } 
  53. +               else
  54. +                   a++; 
  55. +                   b++; 
  56. +               } 
  57. +           } 
  58. +           else
  59. +               a++; 
  60. +               b=0;//start a new check 
  61. +           } 
  62. +        } 
  63. +        if(find==0){ 
  64. +           debug(33, 2) ("there is no \"start\"\n"); 
  65. +           return offset; 
  66. +        } 
  67. +        else { 
  68. +           return 0; 
  69. +        } 
  70. +} 
  71. +static int 
  72. +firstBodyresponse(log_type log_type, squid_off_t firstresponse,size_t size) 
  73. +{ 
  74. +   if(isTcpMiss(log_type)){ 
  75. +       if(firstresponse < 1000){ //1000 is my experience number haha 
  76. +               return 1; 
  77. +           }else { 
  78. +               return 0; 
  79. +           } 
  80. +   }else if(isTcpHit(log_type)){ 
  81. +       if(size != 13 && (firstresponse < 4096)){  
  82. +               return 1; 
  83. +           }else { 
  84. +               return 0; 
  85. +           } 
  86. +   }else 
  87. +       return 0; 
  88. +} 
  89. +static int 
  90. +isTcpMiss(log_type code) 
  91. +{ 
  92. +    /* this should be a bitmap for better optimization */ 
  93. +    if (code == LOG_TCP_MISS) 
  94. +   return 1; 
  95. +    if (code == LOG_TCP_REFRESH_MISS) 
  96. +   return 1; 
  97. +    if (code == LOG_TCP_CLIENT_REFRESH_MISS) 
  98. +   return 1; 
  99. +    if (code == LOG_TCP_SWAPFAIL_MISS) 
  100. +   return 1; 
  101. +    if (code == LOG_TCP_ASYNC_MISS) 
  102. +   return 1; 
  103. +    return 0; 
  104. +} 
  105.  /* Temporary here while restructuring stuff */ 
  106.  static void 
  107.  storeClientCopyHeadersCB(void *data, char *buf, ssize_t size) 
  108. @@ -410,7 +520,7 @@ 
  109.  } 
  110.   
  111.  static StoreEntry * 
  112. -clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags) 
  113. +clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags)//reading from remote disk's drag 
  114.  { 
  115.      StoreEntry *e; 
  116.      /* 
  117. @@ -428,6 +538,7 @@ 
  118.     delaySetStoreClient(h->sc, delayClient(h)); 
  119.  #endif 
  120.      storeClientCopyHeaders(h->sc, e, clientSendHeaders, h); 
  121. +    e->flvstart = h->flvstart; 
  122.      return e; 
  123.  } 
  124.   
  125. @@ -1215,7 +1326,7 @@ 
  126.         MemBuf mb; 
  127.         memBufDefInit(&mb); 
  128.         packerToMemInit(&p, &mb); 
  129. -       httpHeaderPackInto(&request->header, &p); 
  130. +       httpHeaderPackInto(&request->header, &p,0); 
  131.         http->al.headers.request = xstrdup(mb.buf); 
  132.         packerClean(&p); 
  133.         memBufClean(&mb); 
  134. @@ -2089,7 +2200,7 @@ 
  135.     MemBuf mb; 
  136.     memBufDefInit(&mb); 
  137.     packerToMemInit(&p, &mb); 
  138. -   httpHeaderPackInto(&request->header, &p); 
  139. +   httpHeaderPackInto(&request->header, &p,0); 
  140.     al.headers.request = xstrdup(mb.buf); 
  141.     packerClean(&p); 
  142.     memBufClean(&mb); 
  143. @@ -2522,7 +2633,7 @@ 
  144.     httpHeaderPutStr(&hdr, HDR_CONTENT_TYPE, httpHeaderGetStr(&rep->header, HDR_CONTENT_TYPE)); 
  145.      httpHeaderAddContRange(&hdr, *spec, rep->content_length); 
  146.      packerToMemInit(&p, mb); 
  147. -    httpHeaderPackInto(&hdr, &p); 
  148. +    httpHeaderPackInto(&hdr, &p,0); 
  149.      packerClean(&p); 
  150.      httpHeaderClean(&hdr); 
  151.   
  152. @@ -3030,11 +3141,11 @@ 
  153.     if (http->conn->port->http11) { 
  154.         /* enforce 1.1 reply version */ 
  155.         httpBuildVersion(&rep->sline.version, 1, 1); 
  156.         /* enforce 1.0 reply version */ 
  157.         httpBuildVersion(&rep->sline.version, 1, 0); 
  158. -   } 
  159. -   mb = httpReplyPack(rep); 
  160. +      } 
  161. +      mb = httpReplyPack(rep,http->flvstart); 
  162.      } else { 
  163.     debug(33, 2) ("HTTP/0.9 response, disable everything\n"); 
  164.     http->request->flags.chunked_response = 0; 
  165. @@ -3083,6 +3194,7 @@ 
  166.      clientHttpRequest *http = data; 
  167.      StoreEntry *entry = http->entry; 
  168.      ConnStateData *conn = http->conn; 
  169. +    squid_off_t temp = 0; 
  170.      int fd = conn->fd; 
  171.      MemBuf mb; 
  172.      debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size); 
  173. @@ -3111,8 +3223,25 @@ 
  174.      } 
  175.      if (!http->request->range && !http->request->flags.chunked_response) { 
  176.     /* Avoid copying to MemBuf for non-range requests */ 
  177. +    temp = http->out.offset; 
  178.     http->out.offset += size; 
  179. -   comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL); 
  180. +   if (isTcpMiss(http->log_type) == 1 && temp > 0 && temp < 1000 ) {  
  181. +       debug(33, 1) ("clientSendMoreData: http.out.offset is %d, size is %d, temp is %d\n",(int)http->out.offset,(int)size,(int)temp); 
  182. +       debug(33, 1) ("clientSendMoreData: first response body is change to correct offset\n"); 
  183. +       debug(33, 1) ("clientSendMoreData: %s\n",buf); 
  184. +       if (http->flvstart == 9){//this clause is to judge the different start value 
  185. +           size = size - 9; 
  186. +           comm_write(fd, buf+9, size, clientWriteBodyComplete, http, NULL); 
  187. +       }else
  188. +           size = size - 13; 
  189. +           comm_write(fd, buf+13, size, clientWriteBodyComplete, http, NULL); 
  190. +       } 
  191. +   } 
  192. +   else
  193. +       //debug(33, 1) ("clientSendMoreData: %s\n",buf); 
  194. +       comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL); 
  195. +   } 
  196.     /* NULL because clientWriteBodyComplete frees it */ 
  197.     return
  198.      } 
  199. @@ -3165,13 +3294,24 @@ 
  200.   * the headers probably go through here. 
  201.   */ 
  202.  static void 
  203.  { 
  204.      /* 
  205.       * NOTE: clientWriteComplete doesn't currently use its "buf" 
  206.       * (second) argument, so we pass in NULL. 
  207.       */ 
  208. +   clientHttpRequest *http = data; 
  209. +   squid_off_t temp = http->out.offset - size; 
  210. +   if (isTcpMiss(http->log_type) == 1 && temp > 0 && temp < 1000){ 
  211. +   debug(33, 1) ("clientWriteBodyComplete: http->out.offset is %d, temp is %d, size is %d\n",(int)http->out.offset,(int)temp, (int)size); 
  212. +   if (http->flvstart == 9) 
  213. +   memFree(buf-9, MEM_STORE_CLIENT_BUF); 
  214. +   else 
  215. +   memFree(buf-13, MEM_STORE_CLIENT_BUF); 
  216. +   } 
  217. +   else 
  218.      memFree(buf, MEM_STORE_CLIENT_BUF); 
  219.      clientWriteComplete(fd, NULL, size, errflag, data); 
  220.  } 
  221.   
  222. @@ -3233,6 +3373,7 @@ 
  223.      StoreEntry *entry = http->entry; 
  224.      int done; 
  225.      http->out.size += size; 
  226. +    squid_off_t firstresponse = http->out.size; 
  227.      debug(33, 5) ("clientWriteComplete: FD %d, sz %d, err %d, off %" PRINTF_OFF_T ", len %" PRINTF_OFF_T "\n"
  228.     fd, (int) size, errflag, http->out.offset, entry ? objectLen(entry) : (squid_off_t) 0); 
  229.      if (size > 0) { 
  230. @@ -3303,6 +3444,17 @@ 
  231.      } else if (clientReplyBodyTooLarge(http, http->out.offset - 4096)) { 
  232.     /* 4096 is a margin for the HTTP headers included in out.offset */ 
  233.     comm_close(fd); 
  234. +    } else if (firstBodyresponse(http->log_type,firstresponse,size) == 1) { 
  235. +       debug(33, 1) ("clientWriteComplete:  firstresponse is %d, size is %d\n",(int)firstresponse,(int)size); 
  236. +       int response_prefix_len = 13 //13 is the string len of  "FLV\x1\x1\0\0\0\x9\0\0\0\x9" 
  237. +       LOCAL_ARRAY(char, response_prefix, 2048); 
  238. +       memset(response_prefix,0,response_prefix_len); 
  239. +       xmemcpy(response_prefix,"FLV\x1\x1\0\0\0\x9\0\0\0\x9",13); 
  240. +       comm_write(fd, response_prefix, response_prefix_len, clientWriteComplete, http, NULL); 
  241.      } else { 
  242.     /* More data will be coming from primary server; register with  
  243.      * storage manager. */ 
  244. @@ -3870,6 +4022,8 @@ 
  245.         goto invalid_request; 
  246.     } 
  247.      } 
  248. +    http->flvstart = url_get_start(url,"start");  /*get the start value, shunter add this*/ 
  249. +    http->flvstart = http->flvstart ? http->flvstart : 9;//13 is the length of  "FLV\x1\x1\0\0\0\x9\0\0\0\x9";9=13-4 
  250.      if (!http->uri) { 
  251.     /* No special rewrites have been applied above, use the 
  252.      * requested url. may be rewritten later, so make extra room */ 
  253. @@ -4834,7 +4988,8 @@ 
  254.       * objectLen(entry) will be set proprely. 
  255.       */ 
  256.      if (entry->store_status == STORE_OK) { 
  257. -   if (http->out.offset >= objectLen(entry)) 
  258. +    if (http->out.offset + http->flvstart >= objectLen(entry))//modified by shunter 
  259.         return 1; 
  260.     else 
  261.         return 0; 
  262. @@ -5204,3 +5359,6 @@ 
  263.      } 
  264.  } 
  265.  #endif 
  266. --- src/ssl.c   2008-05-05 07:23:13.000000000 +0800 
  267. +++ src/ssl.c   2012-12-27 18:25:09.000000000 +0800 
  268. @@ -600,7 +600,7 @@ 
  269.     &hdr_out, 
  270.     flags);         /* flags */ 
  271.      packerToMemInit(&p, &mb); 
  272. -    httpHeaderPackInto(&hdr_out, &p); 
  273. +    httpHeaderPackInto(&hdr_out, &p,0); 
  274.      httpHeaderClean(&hdr_out); 
  275.      packerClean(&p); 
  276.      memBufAppend(&mb, "\r\n", 2); 
  277. --- src/HttpReply.c 2008-01-23 23:31:51.000000000 +0800 
  278. +++ src/HttpReply.c 2012-12-29 17:15:47.000000000 +0800 
  279. @@ -140,19 +140,24 @@ 
  280.      return (httpReplyParseStep(rep, buf, end) == 1); 
  281.  } 
  282.   
  283.  void 
  284. -httpReplyPackInto(const HttpReply * rep, Packer * p) 
  285. +httpReplyPackInto(const HttpReply * rep, Packer * p,size_t flvstart) 
  286.  { 
  287.      assert(rep); 
  288.      httpStatusLinePackInto(&rep->sline, p); 
  289. -    httpHeaderPackInto(&rep->header, p); 
  290. +    httpHeaderPackInto(&rep->header, p,flvstart); 
  291.      packerAppend(p, "\r\n", 2); 
  292.      httpBodyPackInto(&rep->body, p); 
  293.  } 
  294.  MemBuf 
  295. -httpReplyPack(const HttpReply * rep) 
  296. +httpReplyPack(const HttpReply * rep,size_t flvstart)//shunter 
  297.  { 
  298.      MemBuf mb; 
  299.      Packer p; 
  300. @@ -160,7 +165,7 @@ 
  301.   
  302.      memBufDefInit(&mb); 
  303.      packerToMemInit(&p, &mb); 
  304. -    httpReplyPackInto(rep, &p); 
  305. +    httpReplyPackInto(rep, &p,flvstart); 
  306.      packerClean(&p); 
  307.      return mb; 
  308.  } 
  309. @@ -181,7 +186,7 @@ 
  310.     rep = e->mem_obj->reply; 
  311.      } 
  312.      packerToStoreInit(&p, e); 
  313. -    httpReplyPackInto(e->mem_obj->reply, &p); 
  314. +    httpReplyPackInto(e->mem_obj->reply, &p,0);//shunter 
  315.      packerClean(&p); 
  316.      rep->hdr_sz = e->mem_obj->inmem_hi - rep->body.mb.size; 
  317.  } 
  318. @@ -216,7 +221,7 @@ 
  319.      memBufPrintf(&mb, "HTTP/1.%d 304 Not Modified\r\n", http11); 
  320.      for (t = 0; ImsEntries[t] != HDR_OTHER; ++t) 
  321.     if ((e = httpHeaderFindEntry(&rep->header, ImsEntries[t]))) 
  322. -       httpHeaderEntryPackInto(e, &p); 
  323. +       httpHeaderEntryPackInto(e, &p,0);//shunter 
  324.      memBufAppend(&mb, "\r\n", 2); 
  325.      packerClean(&p); 
  326.      return mb; 
  327. --- src/HttpHeader.c    2008-09-25 10:33:37.000000000 +0800 
  328. +++ src/HttpHeader.c    2013-01-15 10:28:03.000000000 +0800 
  329. @@ -43,7 +43,7 @@ 
  330.   * message-header = field-name ":" [ field-value ] CRLF 
  331.   * field-name     = token 
  332.   * field-value    = *( field-content | LWS ) 
  333. - *  
  334. + * + 
  335.   * HTTP/1.1 does not give a name name a group of all message-headers in a message. 
  336.   * Squid 1.1 seems to refer to that group _plus_ start-line as "headers"
  337.   *  
  338. @@ -572,9 +572,10 @@ 
  339.      return 1;          /* even if no fields where found, it is a valid header */ 
  340.  } 
  341.   
  342. -/* packs all the entries using supplied packer */ 
  343.  void 
  344. -httpHeaderPackInto(const HttpHeader * hdr, Packer * p) 
  345. +httpHeaderPackInto(const HttpHeader * hdr, Packer * p,size_t flvstart) 
  346.  { 
  347.      HttpHeaderPos pos = HttpHeaderInitPos; 
  348.      const HttpHeaderEntry *e; 
  349. @@ -582,7 +583,7 @@ 
  350.      debug(55, 7) ("packing hdr: (%p)\n", hdr); 
  351.      /* pack all entries one by one */ 
  352.      while ((e = httpHeaderGetEntry(hdr, &pos))) 
  353. -   httpHeaderEntryPackInto(e, p); 
  354. +   httpHeaderEntryPackInto(e, p,flvstart);//shunter 
  355.  } 
  356.   
  357.  /* returns next valid entry */ 
  358. @@ -597,7 +598,6 @@ 
  359.      } 
  360.      return NULL; 
  361.  } 
  362.  /* 
  363.   * returns a pointer to a specified entry if any  
  364.   * note that we return one entry so it does not make much sense to ask for 
  365. @@ -1331,12 +1331,19 @@ 
  366.      httpHeaderAddEntry(hdr, httpHeaderEntryClone(e)); 
  367.  } 
  368.   
  369. + 
  370.  void 
  371. -httpHeaderEntryPackInto(const HttpHeaderEntry * e, Packer * p) 
  372. +httpHeaderEntryPackInto(const HttpHeaderEntry * e, Packer * p,size_t flvstart) 
  373.  { 
  374. -    assert(e && p); 
  375. +    char *tmp; 
  376. +   assert(e && p); 
  377.      packerAppend(p, strBuf(e->name), strLen(e->name)); 
  378.      packerAppend(p, ": ", 2); 
  379. +    if(strcmp(e->name.buf,"Content-Length") == 0){ 
  380. +       size_t length=(size_t)strtol(e->value.buf,&tmp,10)-flvstart; 
  381. +       snprintf(e->value.buf,20,"%ld",length); 
  382. +    } 
  383.      packerAppend(p, strBuf(e->value), strLen(e->value)); 
  384.      packerAppend(p, "\r\n", 2); 
  385.  } 
  386. --- src/protos.h    2010-03-08 00:00:07.000000000 +0800 
  387. +++ src/protos.h    2012-12-27 18:23:52.000000000 +0800 
  388. @@ -448,7 +448,7 @@ 
  389.  extern void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask); 
  390.  /* parse/pack */ 
  391.  extern int httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end); 
  392. -extern void httpHeaderPackInto(const HttpHeader * hdr, Packer * p); 
  393. +extern void httpHeaderPackInto(const HttpHeader * hdr, Packer * p,size_t flvstart); 
  394.  /* field manipulation */ 
  395.  extern int httpHeaderHas(const HttpHeader * hdr, http_hdr_type type); 
  396.  extern void httpHeaderPutInt(HttpHeader * hdr, http_hdr_type type, int number); 
  397. @@ -486,7 +486,7 @@ 
  398.  extern void httpHeaderAddEntry(HttpHeader * hdr, HttpHeaderEntry * e); 
  399.  extern void httpHeaderInsertEntry(HttpHeader * hdr, HttpHeaderEntry * e, int pos); 
  400.  extern HttpHeaderEntry *httpHeaderEntryClone(const HttpHeaderEntry * e); 
  401. -extern void httpHeaderEntryPackInto(const HttpHeaderEntry * e, Packer * p); 
  402. +extern void httpHeaderEntryPackInto(const HttpHeaderEntry * e, Packer * p,size_t flvstart); 
  403.  /* store report about current header usage and other stats */ 
  404.  extern void httpHeaderStoreReport(StoreEntry * e); 
  405.  extern void httpHdrMangleList(HttpHeader *, request_t *); 
  406. @@ -504,10 +504,10 @@ 
  407.  extern void httpReplyReset(HttpReply * rep); 
  408.  /* parse returns -1,0,+1 on error,need-more-data,success */ 
  409.  extern int httpReplyParse(HttpReply * rep, const char *buf, size_t); 
  410. -extern void httpReplyPackInto(const HttpReply * rep, Packer * p); 
  411. +extern void httpReplyPackInto(const HttpReply * rep, Packer * p,size_t flvstart);  
  412.  /* ez-routines */ 
  413.  /* mem-pack: returns a ready to use mem buffer with a packed reply */ 
  414. -extern MemBuf httpReplyPack(const HttpReply * rep); 
  415. +extern MemBuf httpReplyPack(const HttpReply * rep,size_t flvstart); 
  416.  /* swap: create swap-based packer, pack, destroy packer and absorbs the reply if not the same as the object reply */ 
  417.  extern void httpReplySwapOut(HttpReply * rep, StoreEntry * e); 
  418.  /* set commonly used info with one call */ 
  419. --- src/store.c 2010-02-14 08:45:52.000000000 +0800 
  420. +++ src/store.c 2013-01-15 17:17:31.000000000 +0800 
  421. @@ -1233,7 +1233,10 @@ 
  422.     store_check_cachable_hist.no.non_get++; 
  423.      } else 
  424.  #endif 
  425. -    if (e->store_status == STORE_OK && EBIT_TEST(e->flags, ENTRY_BAD_LENGTH)) { 
  426. +    if (e->flvstart != 9){//shunter 
  427. +       debug(20, 1) ("storeCheckCachable: start value is not 0,so squid neednot to create entry on disk\n"); 
  428. +    } else if (e->store_status == STORE_OK && EBIT_TEST(e->flags, ENTRY_BAD_LENGTH)) { 
  429.     debug(20, 2) ("storeCheckCachable: NO: wrong content-length\n"); 
  430.     store_check_cachable_hist.no.wrong_content_length++; 
  431.      } else if (EBIT_TEST(e->flags, RELEASE_REQUEST)) { 
  432. --- src/store_client.c  2009-09-17 04:55:26.000000000 +0800 
  433. +++ src/store_client.c  2013-01-05 15:24:39.000000000 +0800 
  434. @@ -180,6 +180,7 @@ 
  435.  #if STORE_CLIENT_LIST_DEBUG 
  436.      assert(sc == storeClientListSearch(e->mem_obj, data)); 
  437.  #endif 
  438. +    clientHttpRequest *http = data;/*added by shunter*/ 
  439.      assert(sc->callback == NULL); 
  440.      assert(sc->entry == e); 
  441.      sc->seen_offset = seen_offset; 
  442. @@ -189,6 +190,7 @@ 
  443.      sc->copy_buf = buf; 
  444.      sc->copy_size = size; 
  445.      sc->copy_offset = copy_offset; 
  446. +    sc->flvstart = http->flvstart;/*added by shunter*/ 
  447.      /* If the read is being deferred, run swapout in case this client has the  
  448.       * lowest seen_offset. storeSwapOut() frees the memory and clears the  
  449.       * ENTRY_DEFER_READ bit if necessary */ 
  450. @@ -347,7 +349,8 @@ 
  451.     storeRead(sc->swapin_sio, 
  452.         sc->copy_buf, 
  453.         sc->copy_size, 
  454. -       sc->copy_offset + mem->swap_hdr_sz, 
  455. +       sc->copy_offset + mem->swap_hdr_sz + sc->flvstart,/*added by shunter*/ 
  456.         storeClientReadBody, 
  457.         sc); 
  458.      } 
  459. --- src/HttpRequest.c   2009-08-17 05:43:51.000000000 +0800 
  460. +++ src/HttpRequest.c   2012-12-27 18:24:37.000000000 +0800 
  461. @@ -116,7 +116,7 @@ 
  462.      packerPrintf(p, "%s %s HTTP/%d.%d\r\n"
  463.     RequestMethods[req->method].str, strBuf(req->urlpath), req->http_ver.major, req->http_ver.minor); 
  464.      /* headers */ 
  465. -    httpHeaderPackInto(&req->header, p); 
  466. +    httpHeaderPackInto(&req->header, p,0); 
  467.      /* trailer */ 
  468.      packerAppend(p, "\r\n", 2); 
  469.  } 
  470. @@ -136,7 +136,7 @@ 
  471.      packerPrintf(p, "%s %s HTTP/%d.%d\r\n"
  472.     RequestMethods[req->method].str, urlCanonical(req), req->http_ver.major, req->http_ver.minor); 
  473.      /* headers */ 
  474. -    httpHeaderPackInto(&req->header, p); 
  475. +    httpHeaderPackInto(&req->header, p,0); 
  476.      /* trailer */ 
  477.      packerAppend(p, "\r\n", 2); 
  478.  } 
  479. --- src/http.c  2009-06-26 06:54:13.000000000 +0800 
  480. +++ src/http.c  2012-12-27 18:22:58.000000000 +0800 
  481. @@ -987,7 +987,7 @@ 
  482.             httpBuildVersion(&reply->sline.version, 0, 9); 
  483.             reply->sline.status = HTTP_OK; 
  484.             httpHeaderPutTime(&reply->header, HDR_DATE, squid_curtime); 
  485. -           mb = httpReplyPack(reply); 
  486. +           mb = httpReplyPack(reply,0); 
  487.             storeAppend(entry, mb.buf, mb.size); 
  488.             storeAppend(entry, httpState->reply_hdr.buf, httpState->reply_hdr.size); 
  489.             memBufClean(&httpState->reply_hdr); 
  490. @@ -1411,7 +1411,7 @@ 
  491.     else 
  492.         request->flags.auth_sent = httpHeaderHas(&hdr, HDR_AUTHORIZATION); 
  493.     packerToMemInit(&p, mb); 
  494. -   httpHeaderPackInto(&hdr, &p); 
  495. +   httpHeaderPackInto(&hdr, &p,0); 
  496.     httpHeaderClean(&hdr); 
  497.     packerClean(&p); 
  498.      } 
  499. --- src/structs.h   2008-09-25 10:33:37.000000000 +0800 
  500. +++ src/structs.h   2013-01-15 17:07:38.000000000 +0800 
  501. @@ -1275,6 +1275,7 @@ 
  502.      STHCB *header_callback;    /* Temporarily here for storeClientCopyHeaders */ 
  503.      StoreEntry *header_entry;  /* Temporarily here for storeClientCopyHeaders */ 
  504.      int is_modified; 
  505. +    size_t flvstart;   /*shunter add this to store the start value of url*/ 
  506.  }; 
  507.   
  508.  struct _ConnStateData { 
  509. @@ -1695,6 +1696,7 @@ 
  510.  #if STORE_CLIENT_LIST_DEBUG 
  511.      void *owner; 
  512.  #endif 
  513. +    size_t flvstart; /*the flv start value added by shunter*/ 
  514.  }; 
  515.   
  516.   
  517. @@ -1794,6 +1796,7 @@ 
  518.      ping_status_t ping_status:3; 
  519.      store_status_t store_status:3; 
  520.      swap_status_t swap_status:3; 
  521. +    size_t flvstart;//shunter 
  522.  }; 
  523.   
  524.  struct _SwapDir { 
  525. --- src/comm.c  2008-06-28 04:56:56.000000000 +0800 
  526. +++ src/comm.c  2013-01-11 17:03:17.000000000 +0800 
  527. @@ -61,6 +61,7 @@ 
  528.  } ConnectStateData; 
  529.   
  530.  /* STATIC */ 
  531. +static int isTcpMiss(log_type code);//shunter 
  532.  static int commBind(int s, struct in_addr, u_short port); 
  533.  static void commSetReuseAddr(int); 
  534.  static void commSetNoLinger(int); 
  535. @@ -81,6 +82,23 @@ 
  536.  static MemPool *comm_write_pool = NULL; 
  537.  static MemPool *conn_close_pool = NULL; 
  538.   
  539. +static int 
  540. +isTcpMiss(log_type code) 
  541. +{ 
  542. +    /* this should be a bitmap for better optimization */ 
  543. +    if (code == LOG_TCP_MISS) 
  544. +   return 1; 
  545. +    if (code == LOG_TCP_REFRESH_MISS) 
  546. +   return 1; 
  547. +    if (code == LOG_TCP_CLIENT_REFRESH_MISS) 
  548. +   return 1; 
  549. +    if (code == LOG_TCP_SWAPFAIL_MISS) 
  550. +   return 1; 
  551. +    if (code == LOG_TCP_ASYNC_MISS) 
  552. +   return 1; 
  553. +    return 0; 
  554. +} 
  555.  static void 
  556.  CommWriteStateCallbackAndFree(int fd, int code) 
  557.  { 
  558. @@ -876,7 +894,7 @@ 
  559.         need_read = 1; 
  560.         break
  561.     case COMM_PENDING_NOW: 
  562. -       need_read = 1;  /* Not really I/O dependent, but this shuld get comm_select to wake up */ 
  563. +       need_read = 1;  /* Not really I/O dependent, but this should get comm_select to wake up */ 
  564.         need_write = 1; 
  565.         break
  566.     }