00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "SpdyCallbacks.h"
00025 #include "SpdyClientSession.h"
00026 #include <arpa/inet.h>
00027
00028 void
00029 spdy_callbacks_init(spdylay_session_callbacks *callbacks)
00030 {
00031 memset(callbacks, 0, sizeof(spdylay_session_callbacks));
00032
00033 callbacks->send_callback = spdy_send_callback;
00034 callbacks->recv_callback = spdy_recv_callback;
00035 callbacks->on_ctrl_recv_callback = spdy_on_ctrl_recv_callback;
00036 callbacks->on_invalid_ctrl_recv_callback = spdy_on_invalid_ctrl_recv_callback;
00037 callbacks->on_data_chunk_recv_callback = spdy_on_data_chunk_recv_callback;
00038 callbacks->on_data_recv_callback = spdy_on_data_recv_callback;
00039 callbacks->before_ctrl_send_callback = spdy_before_ctrl_send_callback;
00040 callbacks->on_ctrl_send_callback = spdy_on_ctrl_send_callback;
00041 callbacks->on_ctrl_not_send_callback = spdy_on_ctrl_not_send_callback;
00042 callbacks->on_data_send_callback = spdy_on_data_send_callback;
00043 callbacks->on_stream_close_callback = spdy_on_stream_close_callback;
00044 callbacks->on_request_recv_callback = spdy_on_request_recv_callback;
00045 callbacks->get_credential_proof = spdy_get_credential_proof;
00046 callbacks->get_credential_ncerts = spdy_get_credential_ncerts;
00047 callbacks->get_credential_cert = spdy_get_credential_cert;
00048 callbacks->on_ctrl_recv_parse_error_callback = spdy_on_ctrl_recv_parse_error_callback;
00049 callbacks->on_unknown_ctrl_recv_callback = spdy_on_unknown_ctrl_recv_callback;
00050 }
00051
00052 void
00053 spdy_prepare_status_response_and_clean_request(SpdyClientSession *sm, int stream_id, const char *status)
00054 {
00055 SpdyRequest *req = sm->req_map[stream_id];
00056 string date_str = http_date(time(0));
00057 const char **nv = new const char*[8+req->headers.size()*2+1];
00058
00059 nv[0] = ":status";
00060 nv[1] = status;
00061 nv[2] = ":version";
00062 nv[3] = "HTTP/1.1";
00063 nv[4] = "server";
00064 nv[5] = SPDYD_SERVER;
00065 nv[6] = "date";
00066 nv[7] = date_str.c_str();
00067
00068 for(size_t i = 0; i < req->headers.size(); ++i) {
00069 nv[8+i*2] = req->headers[i].first.c_str();
00070 nv[8+i*2+1] = req->headers[i].second.c_str();
00071 }
00072 nv[8+req->headers.size()*2] = 0;
00073
00074 int r = spdylay_submit_response(sm->session, stream_id, nv, NULL);
00075 TSAssert(r == 0);
00076
00077 TSVIOReenable(sm->write_vio);
00078 delete [] nv;
00079 sm->cleanup_request(stream_id);
00080 }
00081
00082 static void
00083 spdy_show_data_frame(const char *head_str, spdylay_session * , uint8_t flags,
00084 int32_t stream_id, int32_t length, void *user_data)
00085 {
00086 if (!is_debug_tag_set("spdy"))
00087 return;
00088
00089 SpdyClientSession *sm = (SpdyClientSession *)user_data;
00090
00091 Debug("spdy", "%s DATA frame (sm_id:%" PRIu64 ", stream_id:%d, flag:%d, length:%d)",
00092 head_str, sm->sm_id, stream_id, flags, length);
00093 }
00094
00095 static void
00096 spdy_show_ctl_frame(const char *head_str, spdylay_session * , spdylay_frame_type type,
00097 spdylay_frame *frame, void *user_data)
00098 {
00099 if (!is_debug_tag_set("spdy"))
00100 return;
00101
00102 SpdyClientSession *sm = (SpdyClientSession *)user_data;
00103 switch (type) {
00104 case SPDYLAY_SYN_STREAM: {
00105 spdylay_syn_stream *f = (spdylay_syn_stream *)frame;
00106 Debug("spdy", "%s SYN_STREAM (sm_id:%" PRIu64 ", stream_id:%d, flag:%d, length:%d)",
00107 head_str, sm->sm_id, f->stream_id, f->hd.flags, f->hd.length);
00108 int j, i;
00109 j = i = 0;
00110 while (f->nv[j]) {
00111 Debug("spdy", " %s: %s", f->nv[j], f->nv[j+1]);
00112 i++;
00113 j = 2*i;
00114 }
00115 }
00116 break;
00117 case SPDYLAY_SYN_REPLY: {
00118 spdylay_syn_reply *f = (spdylay_syn_reply *)frame;
00119 Debug("spdy", "%s SYN_REPLY (sm_id:%" PRIu64 ", stream_id:%d, flag:%d, length:%d)",
00120 head_str, sm->sm_id, f->stream_id, f->hd.flags, f->hd.length);
00121 int j, i;
00122 j = i = 0;
00123 while (f->nv[j]) {
00124 Debug("spdy", " %s: %s", f->nv[j], f->nv[j+1]);
00125 i++;
00126 j = 2*i;
00127 }
00128 }
00129 break;
00130 case SPDYLAY_WINDOW_UPDATE: {
00131 spdylay_window_update *f = (spdylay_window_update *)frame;
00132 Debug("spdy", "%s WINDOW_UPDATE (sm_id:%" PRIu64 ", stream_id:%d, flag:%d, delta_window_size:%u)",
00133 head_str, sm->sm_id, f->stream_id, f->hd.flags, f->delta_window_size);
00134 }
00135 break;
00136 case SPDYLAY_SETTINGS: {
00137 spdylay_settings *f = (spdylay_settings *)frame;
00138 Debug("spdy", "%s SETTINGS frame (sm_id:%" PRIu64 ", flag:%d, length:%d, niv:%zu)",
00139 head_str, sm->sm_id, f->hd.flags, f->hd.length, f->niv);
00140 for (size_t i = 0; i < f->niv; i++) {
00141 Debug("spdy", " (%d:%d)", f->iv[i].settings_id, f->iv[i].value);
00142 }
00143 }
00144 break;
00145 case SPDYLAY_HEADERS: {
00146 spdylay_headers *f = (spdylay_headers *)frame;
00147 Debug("spdy", "%s HEADERS frame (sm_id:%" PRIu64 ", stream_id:%d, flag:%d, length:%d)",
00148 head_str, sm->sm_id, f->stream_id, f->hd.flags, f->hd.length);
00149 }
00150 break;
00151 case SPDYLAY_RST_STREAM: {
00152 spdylay_rst_stream *f = (spdylay_rst_stream *)frame;
00153 Debug("spdy", "%s RST_STREAM (sm_id:%" PRIu64 ", stream_id:%d, flag:%d, length:%d, code:%d)",
00154 head_str, sm->sm_id, f->stream_id, f->hd.flags, f->hd.length, f->status_code);
00155 }
00156 break;
00157 case SPDYLAY_GOAWAY: {
00158 spdylay_goaway *f = (spdylay_goaway *)frame;
00159 Debug("spdy", "%s GOAWAY frame (sm_id:%" PRIu64 ", last_good_stream_id:%d, flag:%d, length:%d",
00160 head_str, sm->sm_id, f->last_good_stream_id, f->hd.flags, f->hd.length);
00161 }
00162 default:
00163 break;
00164 }
00165 return;
00166 }
00167
00168 static int
00169 spdy_fetcher_launch(SpdyRequest *req)
00170 {
00171 string url;
00172 int fetch_flags;
00173 const sockaddr *client_addr;
00174 SpdyClientSession *sm = req->spdy_sm;
00175
00176 url = req->scheme + "://" + req->host + req->path;
00177 client_addr = TSNetVConnRemoteAddrGet(reinterpret_cast<TSVConn>(sm->vc));
00178
00179 req->url = url;
00180 Debug("spdy", "++++Request[%" PRIu64 ":%d] %s", sm->sm_id, req->stream_id, req->url.c_str());
00181
00182
00183
00184
00185 fetch_flags = TS_FETCH_FLAGS_DECHUNK;
00186
00187
00188 fetch_flags |= TS_FETCH_FLAGS_NOT_INTERNAL_REQUEST;
00189
00190 req->fetch_sm = TSFetchCreate((TSCont)sm, req->method.c_str(),
00191 url.c_str(), req->version.c_str(),
00192 client_addr, fetch_flags);
00193 TSFetchUserDataSet(req->fetch_sm, req);
00194
00195
00196
00197
00198 for (size_t i = 0; i < req->headers.size(); i++) {
00199
00200 if (*req->headers[i].first.c_str() == ':')
00201 continue;
00202
00203 TSFetchHeaderAdd(req->fetch_sm,
00204 req->headers[i].first.c_str(), req->headers[i].first.size(),
00205 req->headers[i].second.c_str(), req->headers[i].second.size());
00206 }
00207
00208 TSFetchLaunch(req->fetch_sm);
00209 return 0;
00210 }
00211
00212 ssize_t
00213 spdy_send_callback(spdylay_session * , const uint8_t *data, size_t length,
00214 int , void *user_data)
00215 {
00216 SpdyClientSession *sm = (SpdyClientSession*)user_data;
00217
00218 sm->total_size += length;
00219 TSIOBufferWrite(sm->resp_buffer, data, length);
00220
00221 Debug("spdy", "----spdy_send_callback, length:%zu", length);
00222
00223 return length;
00224 }
00225
00226 ssize_t
00227 spdy_recv_callback(spdylay_session * , uint8_t *buf, size_t length,
00228 int , void *user_data)
00229 {
00230 const char *start;
00231 TSIOBufferBlock blk, next_blk;
00232 int64_t already, blk_len, need, wavail;
00233
00234 SpdyClientSession *sm = (SpdyClientSession*)user_data;
00235
00236 already = 0;
00237 blk = TSIOBufferReaderStart(sm->req_reader);
00238
00239 while (blk) {
00240
00241 wavail = length - already;
00242
00243 next_blk = TSIOBufferBlockNext(blk);
00244 start = TSIOBufferBlockReadStart(blk, sm->req_reader, &blk_len);
00245
00246 need = blk_len > wavail ? wavail : blk_len;
00247
00248 memcpy(&buf[already], start, need);
00249 already += need;
00250
00251 if (already >= (int64_t)length)
00252 break;
00253
00254 blk = next_blk;
00255 }
00256
00257 TSIOBufferReaderConsume(sm->req_reader, already);
00258
00259
00260
00261 if (sm->read_vio) {
00262 TSVIOReenable(sm->read_vio);
00263 }
00264
00265 if (!already)
00266 return SPDYLAY_ERR_WOULDBLOCK;
00267
00268 return already;
00269 }
00270
00271 static void
00272 spdy_process_syn_stream_frame(SpdyClientSession *sm, SpdyRequest *req)
00273 {
00274 bool acceptEncodingRecvd = false;
00275
00276 for(size_t i = 0; i < req->headers.size(); ++i) {
00277 const std::string &field = req->headers[i].first;
00278 const std::string &value = req->headers[i].second;
00279
00280 if(field == ":path")
00281 req->path = value;
00282 else if(field == ":method")
00283 req->method = value;
00284 else if(field == ":scheme")
00285 req->scheme = value;
00286 else if(field == ":version")
00287 req->version = value;
00288 else if(field == ":host")
00289 req->host = value;
00290 else if(field == "accept-encoding")
00291 acceptEncodingRecvd = true;
00292 }
00293
00294 if(!req->path.size()|| !req->method.size() || !req->scheme.size()
00295 || !req->version.size() || !req->host.size()) {
00296 spdy_prepare_status_response_and_clean_request(sm, req->stream_id, STATUS_400);
00297 return;
00298 }
00299
00300 if (!acceptEncodingRecvd) {
00301 Debug("spdy", "Accept-Encoding header not received, adding gzip for method %s", req->method.c_str());
00302 req->headers.push_back(make_pair("accept-encoding", "gzip, deflate"));
00303 }
00304
00305 spdy_fetcher_launch(req);
00306 }
00307
00308 void
00309 spdy_on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
00310 spdylay_frame *frame, void *user_data)
00311 {
00312 int stream_id;
00313 SpdyRequest *req;
00314 SpdyClientSession *sm = (SpdyClientSession*)user_data;
00315
00316 spdy_show_ctl_frame("++++RECV", session, type, frame, user_data);
00317
00318 switch (type) {
00319
00320 case SPDYLAY_SYN_STREAM:
00321 stream_id = frame->syn_stream.stream_id;
00322 req = spdyRequestAllocator.alloc();
00323 req->init(sm, stream_id);
00324 req->append_nv(frame->syn_stream.nv);
00325 sm->req_map[stream_id] = req;
00326 spdy_process_syn_stream_frame(sm, req);
00327 break;
00328
00329 case SPDYLAY_HEADERS:
00330 stream_id = frame->syn_stream.stream_id;
00331 req = sm->req_map[stream_id];
00332 req->append_nv(frame->headers.nv);
00333 break;
00334
00335 case SPDYLAY_WINDOW_UPDATE:
00336 TSVIOReenable(sm->write_vio);
00337 break;
00338
00339 default:
00340 break;
00341 }
00342 return;
00343 }
00344
00345 void
00346 spdy_on_invalid_ctrl_recv_callback(spdylay_session * ,
00347 spdylay_frame_type ,
00348 spdylay_frame * ,
00349 uint32_t ,
00350 void * )
00351 {
00352
00353 return;
00354 }
00355
00356 void
00357 spdy_on_data_chunk_recv_callback(spdylay_session * , uint8_t ,
00358 int32_t stream_id, const uint8_t *data,
00359 size_t len, void *user_data)
00360 {
00361 SpdyClientSession *sm = (SpdyClientSession *)user_data;
00362 SpdyRequest *req = sm->find_request(stream_id);
00363
00364
00365
00366
00367 if (!req)
00368 return;
00369
00370 Debug("spdy", "++++Fetcher Append Data, len:%zu", len);
00371 TSFetchWriteData(req->fetch_sm, data, len);
00372
00373 return;
00374 }
00375
00376 void
00377 spdy_on_data_recv_callback(spdylay_session *session, uint8_t flags,
00378 int32_t stream_id, int32_t length, void *user_data)
00379 {
00380 SpdyClientSession *sm = (SpdyClientSession *)user_data;
00381 SpdyRequest *req = sm->find_request(stream_id);
00382
00383 spdy_show_data_frame("++++RECV", session, flags, stream_id, length, user_data);
00384
00385
00386
00387
00388
00389
00390 if (!req) {
00391 TSVIOReenable(sm->write_vio);
00392 return;
00393 }
00394
00395 req->delta_window_size += length;
00396
00397 Debug("spdy", "----sm_id:%" PRId64 ", stream_id:%d, delta_window_size:%u",
00398 sm->sm_id, stream_id, req->delta_window_size);
00399
00400 if (req->delta_window_size >= spdy_initial_window_size/2) {
00401 Debug("spdy", "----Reenable write_vio for WINDOW_UPDATE frame, delta_window_size:%u",
00402 req->delta_window_size);
00403
00404
00405
00406
00407
00408
00409 TSVIOReenable(sm->write_vio);
00410
00411 req->delta_window_size = 0;
00412 }
00413
00414 return;
00415 }
00416
00417 void
00418 spdy_before_ctrl_send_callback(spdylay_session * ,
00419 spdylay_frame_type ,
00420 spdylay_frame * ,
00421 void * )
00422 {
00423
00424 return;
00425 }
00426
00427 void
00428 spdy_on_ctrl_send_callback(spdylay_session *session, spdylay_frame_type type,
00429 spdylay_frame *frame, void *user_data)
00430 {
00431 spdy_show_ctl_frame("----SEND", session, type, frame, user_data);
00432
00433 return;
00434 }
00435
00436 void
00437 spdy_on_ctrl_not_send_callback(spdylay_session * ,
00438 spdylay_frame_type ,
00439 spdylay_frame * ,
00440 int ,
00441 void * )
00442 {
00443
00444 return;
00445 }
00446
00447 void
00448 spdy_on_data_send_callback(spdylay_session *session, uint8_t flags,
00449 int32_t stream_id, int32_t length, void *user_data)
00450 {
00451 SpdyClientSession *sm = (SpdyClientSession *)user_data;
00452
00453 spdy_show_data_frame("----SEND", session, flags, stream_id, length, user_data);
00454
00455 TSVIOReenable(sm->read_vio);
00456 return;
00457 }
00458
00459 void
00460 spdy_on_stream_close_callback(spdylay_session * ,
00461 int32_t ,
00462 spdylay_status_code ,
00463 void * )
00464 {
00465
00466 return;
00467 }
00468
00469 ssize_t
00470 spdy_get_credential_proof(spdylay_session * ,
00471 const spdylay_origin * ,
00472 uint8_t * ,
00473 size_t ,
00474 void * )
00475 {
00476
00477 return 0;
00478 }
00479
00480 ssize_t
00481 spdy_get_credential_ncerts(spdylay_session * ,
00482 const spdylay_origin * ,
00483 void * )
00484 {
00485
00486 return 0;
00487 }
00488
00489 ssize_t
00490 spdy_get_credential_cert(spdylay_session * ,
00491 const spdylay_origin * ,
00492 size_t ,
00493 uint8_t * ,
00494 size_t ,
00495 void * )
00496 {
00497
00498 return 0;
00499 }
00500
00501 void
00502 spdy_on_request_recv_callback(spdylay_session * ,
00503 int32_t ,
00504 void * )
00505 {
00506
00507 return;
00508 }
00509
00510 void
00511 spdy_on_ctrl_recv_parse_error_callback(spdylay_session * ,
00512 spdylay_frame_type ,
00513 const uint8_t * ,
00514 size_t ,
00515 const uint8_t * ,
00516 size_t ,
00517 int ,
00518 void * )
00519 {
00520
00521 return;
00522 }
00523
00524 void
00525 spdy_on_unknown_ctrl_recv_callback(spdylay_session * ,
00526 const uint8_t * ,
00527 size_t ,
00528 const uint8_t * ,
00529 size_t ,
00530 void * )
00531 {
00532
00533 return;
00534 }