最近公司要上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
4. size_t
5.  
6.     UNUSED(srv); 
7.  
8. if (con->mode != DIRECT) return
9.  
10. if (buffer_is_empty(con->physical.path)) return
11.  
12.     mod_flv_streaming_patch_connection(srv, con, p); 
13.  
14.     s_len = con->physical.path->used - 1; 
15.  
16. for
17.         data_string *ds = (data_string *)p->conf.extensions->data[k]; 
18. int
19.  
20. if (ct_len > s_len) continue; 
21. if (ds->value->used == 0) continue; 
22.  
23. if
24.             data_string *get_param; 
25.             stat_cache_entry *sce = NULL; 
26.             buffer *b; 
27. int
28. char
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
38.             } 
39.  
40. /* too short */
41. if (get_param->value->used < 2) return
42.  
43. /* check if it is a number */
44.             start = strtol(get_param->value->ptr, &err, 10); 
45. if (*err != '\0') { 
46. return
47.             } 
48.  
49. if (start <= 0) return
50.  
51. /* check if start is > filesize */
52. if
53. return
54.             } 
55.  
56. if
57. return
58.             } 
59.  
60. /* we are safe now, let's build a flv header */
61.             b = chunkqueue_get_append_buffer(con->write_queue); 
62. "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. "Content-Type"), CONST_STR_LEN("video/x-flv")); 
67.  
68.             con->file_finished = 1; 
69.  
70. return
71.         } 
72.     } 
73.  
74. /* not found */
75. return
76. }

上面是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 要保证对于同一个视频文件磁盘上只出现一个缓存文件,而且这个文件必须是完整的视频文件,不是从某个帧开始的文件。

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

 

android视频可拖动 视频怎么拖动_sed

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