正在显示
10 个修改的文件
包含
1276 行增加
和
1275 行删除
| @@ -36,6 +36,7 @@ using namespace std; | @@ -36,6 +36,7 @@ using namespace std; | ||
| 36 | #include <srs_app_http.hpp> | 36 | #include <srs_app_http.hpp> |
| 37 | #include <srs_app_utility.hpp> | 37 | #include <srs_app_utility.hpp> |
| 38 | #include <srs_core_autofree.hpp> | 38 | #include <srs_core_autofree.hpp> |
| 39 | +#include <srs_app_http_conn.hpp> | ||
| 39 | 40 | ||
| 40 | SrsHttpHeartbeat::SrsHttpHeartbeat() | 41 | SrsHttpHeartbeat::SrsHttpHeartbeat() |
| 41 | { | 42 | { |
| @@ -23,964 +23,3 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -23,964 +23,3 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | 23 | ||
| 24 | #include <srs_app_http.hpp> | 24 | #include <srs_app_http.hpp> |
| 25 | 25 | ||
| 26 | -#ifdef SRS_AUTO_HTTP_PARSER | ||
| 27 | - | ||
| 28 | -#include <sstream> | ||
| 29 | -using namespace std; | ||
| 30 | - | ||
| 31 | -#include <srs_kernel_error.hpp> | ||
| 32 | -#include <srs_kernel_log.hpp> | ||
| 33 | -#include <srs_app_st_socket.hpp> | ||
| 34 | -#include <srs_rtmp_sdk.hpp> | ||
| 35 | -#include <srs_rtmp_buffer.hpp> | ||
| 36 | -#include <srs_kernel_utility.hpp> | ||
| 37 | -#include <srs_rtmp_utility.hpp> | ||
| 38 | -#include <srs_core_autofree.hpp> | ||
| 39 | - | ||
| 40 | -SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io) | ||
| 41 | -{ | ||
| 42 | - skt = io; | ||
| 43 | - hdr = new SrsHttpHeader(); | ||
| 44 | - header_wrote = false; | ||
| 45 | - status = SRS_CONSTS_HTTP_OK; | ||
| 46 | - content_length = -1; | ||
| 47 | - written = 0; | ||
| 48 | - header_sent = false; | ||
| 49 | -} | ||
| 50 | - | ||
| 51 | -SrsHttpResponseWriter::~SrsHttpResponseWriter() | ||
| 52 | -{ | ||
| 53 | - srs_freep(hdr); | ||
| 54 | -} | ||
| 55 | - | ||
| 56 | -int SrsHttpResponseWriter::final_request() | ||
| 57 | -{ | ||
| 58 | - // complete the chunked encoding. | ||
| 59 | - if (content_length == -1) { | ||
| 60 | - std::stringstream ss; | ||
| 61 | - ss << 0 << SRS_HTTP_CRLF << SRS_HTTP_CRLF; | ||
| 62 | - std::string ch = ss.str(); | ||
| 63 | - return skt->write((void*)ch.data(), (int)ch.length(), NULL); | ||
| 64 | - } | ||
| 65 | - | ||
| 66 | - // flush when send with content length | ||
| 67 | - return write(NULL, 0); | ||
| 68 | -} | ||
| 69 | - | ||
| 70 | -SrsHttpHeader* SrsHttpResponseWriter::header() | ||
| 71 | -{ | ||
| 72 | - return hdr; | ||
| 73 | -} | ||
| 74 | - | ||
| 75 | -int SrsHttpResponseWriter::write(char* data, int size) | ||
| 76 | -{ | ||
| 77 | - int ret = ERROR_SUCCESS; | ||
| 78 | - | ||
| 79 | - if (!header_wrote) { | ||
| 80 | - write_header(SRS_CONSTS_HTTP_OK); | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - written += size; | ||
| 84 | - if (content_length != -1 && written > content_length) { | ||
| 85 | - ret = ERROR_HTTP_CONTENT_LENGTH; | ||
| 86 | - srs_error("http: exceed content length. ret=%d", ret); | ||
| 87 | - return ret; | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - if ((ret = send_header(data, size)) != ERROR_SUCCESS) { | ||
| 91 | - srs_error("http: send header failed. ret=%d", ret); | ||
| 92 | - return ret; | ||
| 93 | - } | ||
| 94 | - | ||
| 95 | - // ignore NULL content. | ||
| 96 | - if (!data) { | ||
| 97 | - return ret; | ||
| 98 | - } | ||
| 99 | - | ||
| 100 | - // directly send with content length | ||
| 101 | - if (content_length != -1) { | ||
| 102 | - return skt->write((void*)data, size, NULL); | ||
| 103 | - } | ||
| 104 | - | ||
| 105 | - // send in chunked encoding. | ||
| 106 | - std::stringstream ss; | ||
| 107 | - ss << hex << size << SRS_HTTP_CRLF; | ||
| 108 | - std::string ch = ss.str(); | ||
| 109 | - if ((ret = skt->write((void*)ch.data(), (int)ch.length(), NULL)) != ERROR_SUCCESS) { | ||
| 110 | - return ret; | ||
| 111 | - } | ||
| 112 | - if ((ret = skt->write((void*)data, size, NULL)) != ERROR_SUCCESS) { | ||
| 113 | - return ret; | ||
| 114 | - } | ||
| 115 | - if ((ret = skt->write((void*)SRS_HTTP_CRLF, 2, NULL)) != ERROR_SUCCESS) { | ||
| 116 | - return ret; | ||
| 117 | - } | ||
| 118 | - | ||
| 119 | - return ret; | ||
| 120 | -} | ||
| 121 | - | ||
| 122 | -void SrsHttpResponseWriter::write_header(int code) | ||
| 123 | -{ | ||
| 124 | - if (header_wrote) { | ||
| 125 | - srs_warn("http: multiple write_header calls, code=%d", code); | ||
| 126 | - return; | ||
| 127 | - } | ||
| 128 | - | ||
| 129 | - header_wrote = true; | ||
| 130 | - status = code; | ||
| 131 | - | ||
| 132 | - // parse the content length from header. | ||
| 133 | - content_length = hdr->content_length(); | ||
| 134 | -} | ||
| 135 | - | ||
| 136 | -int SrsHttpResponseWriter::send_header(char* data, int size) | ||
| 137 | -{ | ||
| 138 | - int ret = ERROR_SUCCESS; | ||
| 139 | - | ||
| 140 | - if (header_sent) { | ||
| 141 | - return ret; | ||
| 142 | - } | ||
| 143 | - header_sent = true; | ||
| 144 | - | ||
| 145 | - std::stringstream ss; | ||
| 146 | - | ||
| 147 | - // status_line | ||
| 148 | - ss << "HTTP/1.1 " << status << " " | ||
| 149 | - << srs_generate_http_status_text(status) << SRS_HTTP_CRLF; | ||
| 150 | - | ||
| 151 | - // detect content type | ||
| 152 | - if (srs_go_http_body_allowd(status)) { | ||
| 153 | - if (hdr->content_type().empty()) { | ||
| 154 | - hdr->set_content_type(srs_go_http_detect(data, size)); | ||
| 155 | - } | ||
| 156 | - } | ||
| 157 | - | ||
| 158 | - // set server if not set. | ||
| 159 | - if (hdr->get("Server").empty()) { | ||
| 160 | - hdr->set("Server", RTMP_SIG_SRS_KEY"/"RTMP_SIG_SRS_VERSION); | ||
| 161 | - } | ||
| 162 | - | ||
| 163 | - // chunked encoding | ||
| 164 | - if (content_length == -1) { | ||
| 165 | - hdr->set("Transfer-Encoding", "chunked"); | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - // keep alive to make vlc happy. | ||
| 169 | - hdr->set("Connection", "Keep-Alive"); | ||
| 170 | - | ||
| 171 | - // write headers | ||
| 172 | - hdr->write(ss); | ||
| 173 | - | ||
| 174 | - // header_eof | ||
| 175 | - ss << SRS_HTTP_CRLF; | ||
| 176 | - | ||
| 177 | - std::string buf = ss.str(); | ||
| 178 | - return skt->write((void*)buf.c_str(), buf.length(), NULL); | ||
| 179 | -} | ||
| 180 | - | ||
| 181 | -SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io) | ||
| 182 | -{ | ||
| 183 | - skt = io; | ||
| 184 | - owner = msg; | ||
| 185 | - is_eof = false; | ||
| 186 | - nb_total_read = 0; | ||
| 187 | - nb_left_chunk = 0; | ||
| 188 | - buffer = NULL; | ||
| 189 | -} | ||
| 190 | - | ||
| 191 | -SrsHttpResponseReader::~SrsHttpResponseReader() | ||
| 192 | -{ | ||
| 193 | -} | ||
| 194 | - | ||
| 195 | -int SrsHttpResponseReader::initialize(SrsFastBuffer* body) | ||
| 196 | -{ | ||
| 197 | - int ret = ERROR_SUCCESS; | ||
| 198 | - | ||
| 199 | - nb_chunk = 0; | ||
| 200 | - nb_left_chunk = 0; | ||
| 201 | - nb_total_read = 0; | ||
| 202 | - buffer = body; | ||
| 203 | - | ||
| 204 | - return ret; | ||
| 205 | -} | ||
| 206 | - | ||
| 207 | -bool SrsHttpResponseReader::eof() | ||
| 208 | -{ | ||
| 209 | - return is_eof; | ||
| 210 | -} | ||
| 211 | - | ||
| 212 | -int SrsHttpResponseReader::read(char* data, int nb_data, int* nb_read) | ||
| 213 | -{ | ||
| 214 | - int ret = ERROR_SUCCESS; | ||
| 215 | - | ||
| 216 | - if (is_eof) { | ||
| 217 | - ret = ERROR_HTTP_RESPONSE_EOF; | ||
| 218 | - srs_error("http: response EOF. ret=%d", ret); | ||
| 219 | - return ret; | ||
| 220 | - } | ||
| 221 | - | ||
| 222 | - // chunked encoding. | ||
| 223 | - if (owner->is_chunked()) { | ||
| 224 | - return read_chunked(data, nb_data, nb_read); | ||
| 225 | - } | ||
| 226 | - | ||
| 227 | - // read by specified content-length | ||
| 228 | - int max = (int)owner->content_length() - (int)nb_total_read; | ||
| 229 | - if (max <= 0) { | ||
| 230 | - is_eof = true; | ||
| 231 | - return ret; | ||
| 232 | - } | ||
| 233 | - | ||
| 234 | - // change the max to read. | ||
| 235 | - nb_data = srs_min(nb_data, max); | ||
| 236 | - return read_specified(data, nb_data, nb_read); | ||
| 237 | -} | ||
| 238 | - | ||
| 239 | -int SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb_read) | ||
| 240 | -{ | ||
| 241 | - int ret = ERROR_SUCCESS; | ||
| 242 | - | ||
| 243 | - // when no bytes left in chunk, | ||
| 244 | - // parse the chunk length first. | ||
| 245 | - if (nb_left_chunk <= 0) { | ||
| 246 | - char* at = NULL; | ||
| 247 | - int length = 0; | ||
| 248 | - while (!at) { | ||
| 249 | - // find the CRLF of chunk header end. | ||
| 250 | - char* start = buffer->bytes(); | ||
| 251 | - char* end = start + buffer->size(); | ||
| 252 | - for (char* p = start; p < end - 1; p++) { | ||
| 253 | - if (p[0] == SRS_HTTP_CR && p[1] == SRS_HTTP_LF) { | ||
| 254 | - // invalid chunk, ignore. | ||
| 255 | - if (p == start) { | ||
| 256 | - ret = ERROR_HTTP_INVALID_CHUNK_HEADER; | ||
| 257 | - srs_error("chunk header start with CRLF. ret=%d", ret); | ||
| 258 | - return ret; | ||
| 259 | - } | ||
| 260 | - length = (int)(p - start + 2); | ||
| 261 | - at = buffer->read_slice(length); | ||
| 262 | - break; | ||
| 263 | - } | ||
| 264 | - } | ||
| 265 | - | ||
| 266 | - // got at, ok. | ||
| 267 | - if (at) { | ||
| 268 | - break; | ||
| 269 | - } | ||
| 270 | - | ||
| 271 | - // when empty, only grow 1bytes, but the buffer will cache more. | ||
| 272 | - if ((ret = buffer->grow(skt, buffer->size() + 1)) != ERROR_SUCCESS) { | ||
| 273 | - if (!srs_is_client_gracefully_close(ret)) { | ||
| 274 | - srs_error("read body from server failed. ret=%d", ret); | ||
| 275 | - } | ||
| 276 | - return ret; | ||
| 277 | - } | ||
| 278 | - } | ||
| 279 | - srs_assert(length >= 3); | ||
| 280 | - | ||
| 281 | - // it's ok to set the pos and pos+1 to NULL. | ||
| 282 | - at[length - 1] = 0; | ||
| 283 | - at[length - 2] = 0; | ||
| 284 | - | ||
| 285 | - // size is the bytes size, excludes the chunk header and end CRLF. | ||
| 286 | - int ilength = (int)::strtol(at, NULL, 16); | ||
| 287 | - if (ilength < 0) { | ||
| 288 | - ret = ERROR_HTTP_INVALID_CHUNK_HEADER; | ||
| 289 | - srs_error("chunk header negative, length=%d. ret=%d", ilength, ret); | ||
| 290 | - return ret; | ||
| 291 | - } | ||
| 292 | - | ||
| 293 | - // all bytes in chunk is left now. | ||
| 294 | - nb_chunk = nb_left_chunk = ilength; | ||
| 295 | - } | ||
| 296 | - | ||
| 297 | - if (nb_chunk <= 0) { | ||
| 298 | - // for the last chunk, eof. | ||
| 299 | - is_eof = true; | ||
| 300 | - } else { | ||
| 301 | - // for not the last chunk, there must always exists bytes. | ||
| 302 | - // left bytes in chunk, read some. | ||
| 303 | - srs_assert(nb_left_chunk); | ||
| 304 | - | ||
| 305 | - int nb_bytes = srs_min(nb_left_chunk, nb_data); | ||
| 306 | - ret = read_specified(data, nb_bytes, &nb_bytes); | ||
| 307 | - | ||
| 308 | - // the nb_bytes used for output already read size of bytes. | ||
| 309 | - if (nb_read) { | ||
| 310 | - *nb_read = nb_bytes; | ||
| 311 | - } | ||
| 312 | - nb_left_chunk -= nb_bytes; | ||
| 313 | - srs_info("http: read %d bytes of chunk", nb_bytes); | ||
| 314 | - | ||
| 315 | - // error or still left bytes in chunk, ignore and read in future. | ||
| 316 | - if (nb_left_chunk > 0 || (ret != ERROR_SUCCESS)) { | ||
| 317 | - return ret; | ||
| 318 | - } | ||
| 319 | - srs_info("http: read total chunk %dB", nb_chunk); | ||
| 320 | - } | ||
| 321 | - | ||
| 322 | - // for both the last or not, the CRLF of chunk payload end. | ||
| 323 | - if ((ret = buffer->grow(skt, 2)) != ERROR_SUCCESS) { | ||
| 324 | - if (!srs_is_client_gracefully_close(ret)) { | ||
| 325 | - srs_error("read EOF of chunk from server failed. ret=%d", ret); | ||
| 326 | - } | ||
| 327 | - return ret; | ||
| 328 | - } | ||
| 329 | - buffer->read_slice(2); | ||
| 330 | - | ||
| 331 | - return ret; | ||
| 332 | -} | ||
| 333 | - | ||
| 334 | -int SrsHttpResponseReader::read_specified(char* data, int nb_data, int* nb_read) | ||
| 335 | -{ | ||
| 336 | - int ret = ERROR_SUCCESS; | ||
| 337 | - | ||
| 338 | - if (buffer->size() <= 0) { | ||
| 339 | - // when empty, only grow 1bytes, but the buffer will cache more. | ||
| 340 | - if ((ret = buffer->grow(skt, 1)) != ERROR_SUCCESS) { | ||
| 341 | - if (!srs_is_client_gracefully_close(ret)) { | ||
| 342 | - srs_error("read body from server failed. ret=%d", ret); | ||
| 343 | - } | ||
| 344 | - return ret; | ||
| 345 | - } | ||
| 346 | - } | ||
| 347 | - | ||
| 348 | - int nb_bytes = srs_min(nb_data, buffer->size()); | ||
| 349 | - | ||
| 350 | - // read data to buffer. | ||
| 351 | - srs_assert(nb_bytes); | ||
| 352 | - char* p = buffer->read_slice(nb_bytes); | ||
| 353 | - memcpy(data, p, nb_bytes); | ||
| 354 | - if (nb_read) { | ||
| 355 | - *nb_read = nb_bytes; | ||
| 356 | - } | ||
| 357 | - | ||
| 358 | - // increase the total read to determine whether EOF. | ||
| 359 | - nb_total_read += nb_bytes; | ||
| 360 | - | ||
| 361 | - // for not chunked | ||
| 362 | - if (!owner->is_chunked()) { | ||
| 363 | - // when read completed, eof. | ||
| 364 | - if (nb_total_read >= (int)owner->content_length()) { | ||
| 365 | - is_eof = true; | ||
| 366 | - } | ||
| 367 | - } | ||
| 368 | - | ||
| 369 | - return ret; | ||
| 370 | -} | ||
| 371 | - | ||
| 372 | -SrsHttpMessage::SrsHttpMessage(SrsStSocket* io, SrsConnection* c) : ISrsHttpMessage() | ||
| 373 | -{ | ||
| 374 | - conn = c; | ||
| 375 | - chunked = false; | ||
| 376 | - keep_alive = true; | ||
| 377 | - _uri = new SrsHttpUri(); | ||
| 378 | - _body = new SrsHttpResponseReader(this, io); | ||
| 379 | - _http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE]; | ||
| 380 | -} | ||
| 381 | - | ||
| 382 | -SrsHttpMessage::~SrsHttpMessage() | ||
| 383 | -{ | ||
| 384 | - srs_freep(_body); | ||
| 385 | - srs_freep(_uri); | ||
| 386 | - srs_freep(_http_ts_send_buffer); | ||
| 387 | -} | ||
| 388 | - | ||
| 389 | -int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body, vector<SrsHttpHeaderField>& headers) | ||
| 390 | -{ | ||
| 391 | - int ret = ERROR_SUCCESS; | ||
| 392 | - | ||
| 393 | - _url = url; | ||
| 394 | - _header = *header; | ||
| 395 | - _headers = headers; | ||
| 396 | - | ||
| 397 | - // whether chunked. | ||
| 398 | - std::string transfer_encoding = get_request_header("Transfer-Encoding"); | ||
| 399 | - chunked = (transfer_encoding == "chunked"); | ||
| 400 | - | ||
| 401 | - // whether keep alive. | ||
| 402 | - keep_alive = http_should_keep_alive(header); | ||
| 403 | - | ||
| 404 | - // set the buffer. | ||
| 405 | - if ((ret = _body->initialize(body)) != ERROR_SUCCESS) { | ||
| 406 | - return ret; | ||
| 407 | - } | ||
| 408 | - | ||
| 409 | - // parse uri from url. | ||
| 410 | - std::string host = get_request_header("Host"); | ||
| 411 | - | ||
| 412 | - // donot parse the empty host for uri, | ||
| 413 | - // for example, the response contains no host, | ||
| 414 | - // ignore it is ok. | ||
| 415 | - if (host.empty()) { | ||
| 416 | - return ret; | ||
| 417 | - } | ||
| 418 | - | ||
| 419 | - // parse uri to schema/server:port/path?query | ||
| 420 | - std::string uri = "http://" + host + _url; | ||
| 421 | - if ((ret = _uri->initialize(uri)) != ERROR_SUCCESS) { | ||
| 422 | - return ret; | ||
| 423 | - } | ||
| 424 | - | ||
| 425 | - // must format as key=value&...&keyN=valueN | ||
| 426 | - std::string q = _uri->get_query(); | ||
| 427 | - size_t pos = string::npos; | ||
| 428 | - while (!q.empty()) { | ||
| 429 | - std::string k = q; | ||
| 430 | - if ((pos = q.find("=")) != string::npos) { | ||
| 431 | - k = q.substr(0, pos); | ||
| 432 | - q = q.substr(pos + 1); | ||
| 433 | - } else { | ||
| 434 | - q = ""; | ||
| 435 | - } | ||
| 436 | - | ||
| 437 | - std::string v = q; | ||
| 438 | - if ((pos = q.find("&")) != string::npos) { | ||
| 439 | - v = q.substr(0, pos); | ||
| 440 | - q = q.substr(pos + 1); | ||
| 441 | - } else { | ||
| 442 | - q = ""; | ||
| 443 | - } | ||
| 444 | - | ||
| 445 | - _query[k] = v; | ||
| 446 | - } | ||
| 447 | - | ||
| 448 | - // parse ext. | ||
| 449 | - _ext = _uri->get_path(); | ||
| 450 | - if ((pos = _ext.rfind(".")) != string::npos) { | ||
| 451 | - _ext = _ext.substr(pos); | ||
| 452 | - } else { | ||
| 453 | - _ext = ""; | ||
| 454 | - } | ||
| 455 | - | ||
| 456 | - return ret; | ||
| 457 | -} | ||
| 458 | - | ||
| 459 | -SrsConnection* SrsHttpMessage::connection() | ||
| 460 | -{ | ||
| 461 | - return conn; | ||
| 462 | -} | ||
| 463 | - | ||
| 464 | -u_int8_t SrsHttpMessage::method() | ||
| 465 | -{ | ||
| 466 | - return (u_int8_t)_header.method; | ||
| 467 | -} | ||
| 468 | - | ||
| 469 | -u_int16_t SrsHttpMessage::status_code() | ||
| 470 | -{ | ||
| 471 | - return (u_int16_t)_header.status_code; | ||
| 472 | -} | ||
| 473 | - | ||
| 474 | -string SrsHttpMessage::method_str() | ||
| 475 | -{ | ||
| 476 | - if (is_http_get()) { | ||
| 477 | - return "GET"; | ||
| 478 | - } | ||
| 479 | - if (is_http_put()) { | ||
| 480 | - return "PUT"; | ||
| 481 | - } | ||
| 482 | - if (is_http_post()) { | ||
| 483 | - return "POST"; | ||
| 484 | - } | ||
| 485 | - if (is_http_delete()) { | ||
| 486 | - return "DELETE"; | ||
| 487 | - } | ||
| 488 | - if (is_http_options()) { | ||
| 489 | - return "OPTIONS"; | ||
| 490 | - } | ||
| 491 | - | ||
| 492 | - return "OTHER"; | ||
| 493 | -} | ||
| 494 | - | ||
| 495 | -bool SrsHttpMessage::is_http_get() | ||
| 496 | -{ | ||
| 497 | - return _header.method == SRS_CONSTS_HTTP_GET; | ||
| 498 | -} | ||
| 499 | - | ||
| 500 | -bool SrsHttpMessage::is_http_put() | ||
| 501 | -{ | ||
| 502 | - return _header.method == SRS_CONSTS_HTTP_PUT; | ||
| 503 | -} | ||
| 504 | - | ||
| 505 | -bool SrsHttpMessage::is_http_post() | ||
| 506 | -{ | ||
| 507 | - return _header.method == SRS_CONSTS_HTTP_POST; | ||
| 508 | -} | ||
| 509 | - | ||
| 510 | -bool SrsHttpMessage::is_http_delete() | ||
| 511 | -{ | ||
| 512 | - return _header.method == SRS_CONSTS_HTTP_DELETE; | ||
| 513 | -} | ||
| 514 | - | ||
| 515 | -bool SrsHttpMessage::is_http_options() | ||
| 516 | -{ | ||
| 517 | - return _header.method == SRS_CONSTS_HTTP_OPTIONS; | ||
| 518 | -} | ||
| 519 | - | ||
| 520 | -bool SrsHttpMessage::is_chunked() | ||
| 521 | -{ | ||
| 522 | - return chunked; | ||
| 523 | -} | ||
| 524 | - | ||
| 525 | -bool SrsHttpMessage::is_keep_alive() | ||
| 526 | -{ | ||
| 527 | - return keep_alive; | ||
| 528 | -} | ||
| 529 | - | ||
| 530 | -string SrsHttpMessage::uri() | ||
| 531 | -{ | ||
| 532 | - std::string uri = _uri->get_schema(); | ||
| 533 | - if (uri.empty()) { | ||
| 534 | - uri += "http"; | ||
| 535 | - } | ||
| 536 | - uri += "://"; | ||
| 537 | - | ||
| 538 | - uri += host(); | ||
| 539 | - uri += path(); | ||
| 540 | - return uri; | ||
| 541 | -} | ||
| 542 | - | ||
| 543 | -string SrsHttpMessage::url() | ||
| 544 | -{ | ||
| 545 | - return _uri->get_url(); | ||
| 546 | -} | ||
| 547 | - | ||
| 548 | -string SrsHttpMessage::host() | ||
| 549 | -{ | ||
| 550 | - return _uri->get_host(); | ||
| 551 | -} | ||
| 552 | - | ||
| 553 | -string SrsHttpMessage::path() | ||
| 554 | -{ | ||
| 555 | - return _uri->get_path(); | ||
| 556 | -} | ||
| 557 | - | ||
| 558 | -string SrsHttpMessage::ext() | ||
| 559 | -{ | ||
| 560 | - return _ext; | ||
| 561 | -} | ||
| 562 | - | ||
| 563 | -int SrsHttpMessage::body_read_all(string& body) | ||
| 564 | -{ | ||
| 565 | - int ret = ERROR_SUCCESS; | ||
| 566 | - | ||
| 567 | - // cache to read. | ||
| 568 | - char* buf = new char[SRS_HTTP_READ_CACHE_BYTES]; | ||
| 569 | - SrsAutoFree(char, buf); | ||
| 570 | - | ||
| 571 | - // whatever, read util EOF. | ||
| 572 | - while (!_body->eof()) { | ||
| 573 | - int nb_read = 0; | ||
| 574 | - if ((ret = _body->read(buf, SRS_HTTP_READ_CACHE_BYTES, &nb_read)) != ERROR_SUCCESS) { | ||
| 575 | - return ret; | ||
| 576 | - } | ||
| 577 | - | ||
| 578 | - if (nb_read > 0) { | ||
| 579 | - body.append(buf, nb_read); | ||
| 580 | - } | ||
| 581 | - } | ||
| 582 | - | ||
| 583 | - return ret; | ||
| 584 | -} | ||
| 585 | - | ||
| 586 | -ISrsHttpResponseReader* SrsHttpMessage::body_reader() | ||
| 587 | -{ | ||
| 588 | - return _body; | ||
| 589 | -} | ||
| 590 | - | ||
| 591 | -int64_t SrsHttpMessage::content_length() | ||
| 592 | -{ | ||
| 593 | - return _header.content_length; | ||
| 594 | -} | ||
| 595 | - | ||
| 596 | -string SrsHttpMessage::query_get(string key) | ||
| 597 | -{ | ||
| 598 | - std::string v; | ||
| 599 | - | ||
| 600 | - if (_query.find(key) != _query.end()) { | ||
| 601 | - v = _query[key]; | ||
| 602 | - } | ||
| 603 | - | ||
| 604 | - return v; | ||
| 605 | -} | ||
| 606 | - | ||
| 607 | -int SrsHttpMessage::request_header_count() | ||
| 608 | -{ | ||
| 609 | - return (int)_headers.size(); | ||
| 610 | -} | ||
| 611 | - | ||
| 612 | -string SrsHttpMessage::request_header_key_at(int index) | ||
| 613 | -{ | ||
| 614 | - srs_assert(index < request_header_count()); | ||
| 615 | - SrsHttpHeaderField item = _headers[index]; | ||
| 616 | - return item.first; | ||
| 617 | -} | ||
| 618 | - | ||
| 619 | -string SrsHttpMessage::request_header_value_at(int index) | ||
| 620 | -{ | ||
| 621 | - srs_assert(index < request_header_count()); | ||
| 622 | - SrsHttpHeaderField item = _headers[index]; | ||
| 623 | - return item.second; | ||
| 624 | -} | ||
| 625 | - | ||
| 626 | -string SrsHttpMessage::get_request_header(string name) | ||
| 627 | -{ | ||
| 628 | - std::vector<SrsHttpHeaderField>::iterator it; | ||
| 629 | - | ||
| 630 | - for (it = _headers.begin(); it != _headers.end(); ++it) { | ||
| 631 | - SrsHttpHeaderField& elem = *it; | ||
| 632 | - std::string key = elem.first; | ||
| 633 | - std::string value = elem.second; | ||
| 634 | - if (key == name) { | ||
| 635 | - return value; | ||
| 636 | - } | ||
| 637 | - } | ||
| 638 | - | ||
| 639 | - return ""; | ||
| 640 | -} | ||
| 641 | - | ||
| 642 | -SrsRequest* SrsHttpMessage::to_request(string vhost) | ||
| 643 | -{ | ||
| 644 | - SrsRequest* req = new SrsRequest(); | ||
| 645 | - | ||
| 646 | - req->app = _uri->get_path(); | ||
| 647 | - size_t pos = string::npos; | ||
| 648 | - if ((pos = req->app.rfind("/")) != string::npos) { | ||
| 649 | - req->stream = req->app.substr(pos + 1); | ||
| 650 | - req->app = req->app.substr(0, pos); | ||
| 651 | - } | ||
| 652 | - if ((pos = req->stream.rfind(".")) != string::npos) { | ||
| 653 | - req->stream = req->stream.substr(0, pos); | ||
| 654 | - } | ||
| 655 | - | ||
| 656 | - req->tcUrl = "rtmp://" + vhost + req->app; | ||
| 657 | - req->pageUrl = get_request_header("Referer"); | ||
| 658 | - req->objectEncoding = 0; | ||
| 659 | - | ||
| 660 | - srs_discovery_tc_url(req->tcUrl, | ||
| 661 | - req->schema, req->host, req->vhost, req->app, req->port, | ||
| 662 | - req->param); | ||
| 663 | - req->strip(); | ||
| 664 | - | ||
| 665 | - return req; | ||
| 666 | -} | ||
| 667 | - | ||
| 668 | -SrsHttpParser::SrsHttpParser() | ||
| 669 | -{ | ||
| 670 | - buffer = new SrsFastBuffer(); | ||
| 671 | -} | ||
| 672 | - | ||
| 673 | -SrsHttpParser::~SrsHttpParser() | ||
| 674 | -{ | ||
| 675 | - srs_freep(buffer); | ||
| 676 | -} | ||
| 677 | - | ||
| 678 | -int SrsHttpParser::initialize(enum http_parser_type type) | ||
| 679 | -{ | ||
| 680 | - int ret = ERROR_SUCCESS; | ||
| 681 | - | ||
| 682 | - memset(&settings, 0, sizeof(settings)); | ||
| 683 | - settings.on_message_begin = on_message_begin; | ||
| 684 | - settings.on_url = on_url; | ||
| 685 | - settings.on_header_field = on_header_field; | ||
| 686 | - settings.on_header_value = on_header_value; | ||
| 687 | - settings.on_headers_complete = on_headers_complete; | ||
| 688 | - settings.on_body = on_body; | ||
| 689 | - settings.on_message_complete = on_message_complete; | ||
| 690 | - | ||
| 691 | - http_parser_init(&parser, type); | ||
| 692 | - // callback object ptr. | ||
| 693 | - parser.data = (void*)this; | ||
| 694 | - | ||
| 695 | - return ret; | ||
| 696 | -} | ||
| 697 | - | ||
| 698 | -int SrsHttpParser::parse_message(SrsStSocket* skt, SrsConnection* conn, ISrsHttpMessage** ppmsg) | ||
| 699 | -{ | ||
| 700 | - *ppmsg = NULL; | ||
| 701 | - | ||
| 702 | - int ret = ERROR_SUCCESS; | ||
| 703 | - | ||
| 704 | - // reset request data. | ||
| 705 | - field_name = ""; | ||
| 706 | - field_value = ""; | ||
| 707 | - expect_field_name = true; | ||
| 708 | - state = SrsHttpParseStateInit; | ||
| 709 | - header = http_parser(); | ||
| 710 | - url = ""; | ||
| 711 | - headers.clear(); | ||
| 712 | - header_parsed = 0; | ||
| 713 | - | ||
| 714 | - // do parse | ||
| 715 | - if ((ret = parse_message_imp(skt)) != ERROR_SUCCESS) { | ||
| 716 | - if (!srs_is_client_gracefully_close(ret)) { | ||
| 717 | - srs_error("parse http msg failed. ret=%d", ret); | ||
| 718 | - } | ||
| 719 | - return ret; | ||
| 720 | - } | ||
| 721 | - | ||
| 722 | - // create msg | ||
| 723 | - SrsHttpMessage* msg = new SrsHttpMessage(skt, conn); | ||
| 724 | - | ||
| 725 | - // initalize http msg, parse url. | ||
| 726 | - if ((ret = msg->update(url, &header, buffer, headers)) != ERROR_SUCCESS) { | ||
| 727 | - srs_error("initialize http msg failed. ret=%d", ret); | ||
| 728 | - srs_freep(msg); | ||
| 729 | - return ret; | ||
| 730 | - } | ||
| 731 | - | ||
| 732 | - // parse ok, return the msg. | ||
| 733 | - *ppmsg = msg; | ||
| 734 | - | ||
| 735 | - return ret; | ||
| 736 | -} | ||
| 737 | - | ||
| 738 | -int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | ||
| 739 | -{ | ||
| 740 | - int ret = ERROR_SUCCESS; | ||
| 741 | - | ||
| 742 | - while (true) { | ||
| 743 | - ssize_t nparsed = 0; | ||
| 744 | - | ||
| 745 | - // when got entire http header, parse it. | ||
| 746 | - // @see https://github.com/simple-rtmp-server/srs/issues/400 | ||
| 747 | - char* start = buffer->bytes(); | ||
| 748 | - char* end = start + buffer->size(); | ||
| 749 | - for (char* p = start; p <= end - 4; p++) { | ||
| 750 | - // SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A | ||
| 751 | - if (p[0] == SRS_CONSTS_CR && p[1] == SRS_CONSTS_LF && p[2] == SRS_CONSTS_CR && p[3] == SRS_CONSTS_LF) { | ||
| 752 | - nparsed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size()); | ||
| 753 | - srs_info("buffer=%d, nparsed=%d, header=%d", buffer->size(), (int)nparsed, header_parsed); | ||
| 754 | - break; | ||
| 755 | - } | ||
| 756 | - } | ||
| 757 | - | ||
| 758 | - // consume the parsed bytes. | ||
| 759 | - if (nparsed && header_parsed) { | ||
| 760 | - buffer->read_slice(header_parsed); | ||
| 761 | - } | ||
| 762 | - | ||
| 763 | - // ok atleast header completed, | ||
| 764 | - // never wait for body completed, for maybe chunked. | ||
| 765 | - if (state == SrsHttpParseStateHeaderComplete || state == SrsHttpParseStateMessageComplete) { | ||
| 766 | - break; | ||
| 767 | - } | ||
| 768 | - | ||
| 769 | - // when nothing parsed, read more to parse. | ||
| 770 | - if (nparsed == 0) { | ||
| 771 | - // when requires more, only grow 1bytes, but the buffer will cache more. | ||
| 772 | - if ((ret = buffer->grow(skt, buffer->size() + 1)) != ERROR_SUCCESS) { | ||
| 773 | - if (!srs_is_client_gracefully_close(ret)) { | ||
| 774 | - srs_error("read body from server failed. ret=%d", ret); | ||
| 775 | - } | ||
| 776 | - return ret; | ||
| 777 | - } | ||
| 778 | - } | ||
| 779 | - } | ||
| 780 | - | ||
| 781 | - // parse last header. | ||
| 782 | - if (!field_name.empty() && !field_value.empty()) { | ||
| 783 | - headers.push_back(std::make_pair(field_name, field_value)); | ||
| 784 | - } | ||
| 785 | - | ||
| 786 | - return ret; | ||
| 787 | -} | ||
| 788 | - | ||
| 789 | -int SrsHttpParser::on_message_begin(http_parser* parser) | ||
| 790 | -{ | ||
| 791 | - SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 792 | - srs_assert(obj); | ||
| 793 | - | ||
| 794 | - obj->state = SrsHttpParseStateStart; | ||
| 795 | - | ||
| 796 | - srs_info("***MESSAGE BEGIN***"); | ||
| 797 | - | ||
| 798 | - return 0; | ||
| 799 | -} | ||
| 800 | - | ||
| 801 | -int SrsHttpParser::on_headers_complete(http_parser* parser) | ||
| 802 | -{ | ||
| 803 | - SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 804 | - srs_assert(obj); | ||
| 805 | - | ||
| 806 | - obj->header = *parser; | ||
| 807 | - // save the parser when header parse completed. | ||
| 808 | - obj->state = SrsHttpParseStateHeaderComplete; | ||
| 809 | - obj->header_parsed = (int)parser->nread; | ||
| 810 | - | ||
| 811 | - srs_info("***HEADERS COMPLETE***"); | ||
| 812 | - | ||
| 813 | - // see http_parser.c:1570, return 1 to skip body. | ||
| 814 | - return 0; | ||
| 815 | -} | ||
| 816 | - | ||
| 817 | -int SrsHttpParser::on_message_complete(http_parser* parser) | ||
| 818 | -{ | ||
| 819 | - SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 820 | - srs_assert(obj); | ||
| 821 | - | ||
| 822 | - // save the parser when body parse completed. | ||
| 823 | - obj->state = SrsHttpParseStateMessageComplete; | ||
| 824 | - | ||
| 825 | - srs_info("***MESSAGE COMPLETE***\n"); | ||
| 826 | - | ||
| 827 | - return 0; | ||
| 828 | -} | ||
| 829 | - | ||
| 830 | -int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length) | ||
| 831 | -{ | ||
| 832 | - SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 833 | - srs_assert(obj); | ||
| 834 | - | ||
| 835 | - if (length > 0) { | ||
| 836 | - obj->url.append(at, (int)length); | ||
| 837 | - } | ||
| 838 | - | ||
| 839 | - srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at); | ||
| 840 | - | ||
| 841 | - return 0; | ||
| 842 | -} | ||
| 843 | - | ||
| 844 | -int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t length) | ||
| 845 | -{ | ||
| 846 | - SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 847 | - srs_assert(obj); | ||
| 848 | - | ||
| 849 | - // field value=>name, reap the field. | ||
| 850 | - if (!obj->expect_field_name) { | ||
| 851 | - obj->headers.push_back(std::make_pair(obj->field_name, obj->field_value)); | ||
| 852 | - | ||
| 853 | - // reset the field name when parsed. | ||
| 854 | - obj->field_name = ""; | ||
| 855 | - obj->field_value = ""; | ||
| 856 | - } | ||
| 857 | - obj->expect_field_name = true; | ||
| 858 | - | ||
| 859 | - if (length > 0) { | ||
| 860 | - obj->field_name.append(at, (int)length); | ||
| 861 | - } | ||
| 862 | - | ||
| 863 | - srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at); | ||
| 864 | - return 0; | ||
| 865 | -} | ||
| 866 | - | ||
| 867 | -int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t length) | ||
| 868 | -{ | ||
| 869 | - SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 870 | - srs_assert(obj); | ||
| 871 | - | ||
| 872 | - if (length > 0) { | ||
| 873 | - obj->field_value.append(at, (int)length); | ||
| 874 | - } | ||
| 875 | - obj->expect_field_name = false; | ||
| 876 | - | ||
| 877 | - srs_info("Header value(%d bytes): %.*s", (int)length, (int)length, at); | ||
| 878 | - return 0; | ||
| 879 | -} | ||
| 880 | - | ||
| 881 | -int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length) | ||
| 882 | -{ | ||
| 883 | - SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 884 | - srs_assert(obj); | ||
| 885 | - | ||
| 886 | - srs_info("Body: %.*s", (int)length, at); | ||
| 887 | - | ||
| 888 | - return 0; | ||
| 889 | -} | ||
| 890 | - | ||
| 891 | -SrsHttpUri::SrsHttpUri() | ||
| 892 | -{ | ||
| 893 | - port = SRS_DEFAULT_HTTP_PORT; | ||
| 894 | -} | ||
| 895 | - | ||
| 896 | -SrsHttpUri::~SrsHttpUri() | ||
| 897 | -{ | ||
| 898 | -} | ||
| 899 | - | ||
| 900 | -int SrsHttpUri::initialize(string _url) | ||
| 901 | -{ | ||
| 902 | - int ret = ERROR_SUCCESS; | ||
| 903 | - | ||
| 904 | - url = _url; | ||
| 905 | - const char* purl = url.c_str(); | ||
| 906 | - | ||
| 907 | - http_parser_url hp_u; | ||
| 908 | - if((ret = http_parser_parse_url(purl, url.length(), 0, &hp_u)) != 0){ | ||
| 909 | - int code = ret; | ||
| 910 | - ret = ERROR_HTTP_PARSE_URI; | ||
| 911 | - | ||
| 912 | - srs_error("parse url %s failed, code=%d, ret=%d", purl, code, ret); | ||
| 913 | - return ret; | ||
| 914 | - } | ||
| 915 | - | ||
| 916 | - std::string field = get_uri_field(url, &hp_u, UF_SCHEMA); | ||
| 917 | - if(!field.empty()){ | ||
| 918 | - schema = field; | ||
| 919 | - } | ||
| 920 | - | ||
| 921 | - host = get_uri_field(url, &hp_u, UF_HOST); | ||
| 922 | - | ||
| 923 | - field = get_uri_field(url, &hp_u, UF_PORT); | ||
| 924 | - if(!field.empty()){ | ||
| 925 | - port = atoi(field.c_str()); | ||
| 926 | - } | ||
| 927 | - | ||
| 928 | - path = get_uri_field(url, &hp_u, UF_PATH); | ||
| 929 | - srs_info("parse url %s success", purl); | ||
| 930 | - | ||
| 931 | - query = get_uri_field(url, &hp_u, UF_QUERY); | ||
| 932 | - srs_info("parse query %s success", query.c_str()); | ||
| 933 | - | ||
| 934 | - return ret; | ||
| 935 | -} | ||
| 936 | - | ||
| 937 | -const char* SrsHttpUri::get_url() | ||
| 938 | -{ | ||
| 939 | - return url.data(); | ||
| 940 | -} | ||
| 941 | - | ||
| 942 | -const char* SrsHttpUri::get_schema() | ||
| 943 | -{ | ||
| 944 | - return schema.data(); | ||
| 945 | -} | ||
| 946 | - | ||
| 947 | -const char* SrsHttpUri::get_host() | ||
| 948 | -{ | ||
| 949 | - return host.data(); | ||
| 950 | -} | ||
| 951 | - | ||
| 952 | -int SrsHttpUri::get_port() | ||
| 953 | -{ | ||
| 954 | - return port; | ||
| 955 | -} | ||
| 956 | - | ||
| 957 | -const char* SrsHttpUri::get_path() | ||
| 958 | -{ | ||
| 959 | - return path.data(); | ||
| 960 | -} | ||
| 961 | - | ||
| 962 | -const char* SrsHttpUri::get_query() | ||
| 963 | -{ | ||
| 964 | - return query.data(); | ||
| 965 | -} | ||
| 966 | - | ||
| 967 | -string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field) | ||
| 968 | -{ | ||
| 969 | - if((hp_u->field_set & (1 << field)) == 0){ | ||
| 970 | - return ""; | ||
| 971 | - } | ||
| 972 | - | ||
| 973 | - srs_verbose("uri field matched, off=%d, len=%d, value=%.*s", | ||
| 974 | - hp_u->field_data[field].off, | ||
| 975 | - hp_u->field_data[field].len, | ||
| 976 | - hp_u->field_data[field].len, | ||
| 977 | - uri.c_str() + hp_u->field_data[field].off); | ||
| 978 | - | ||
| 979 | - int offset = hp_u->field_data[field].off; | ||
| 980 | - int len = hp_u->field_data[field].len; | ||
| 981 | - | ||
| 982 | - return uri.substr(offset, len); | ||
| 983 | -} | ||
| 984 | - | ||
| 985 | -#endif | ||
| 986 | - |
| @@ -29,314 +29,4 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -29,314 +29,4 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 29 | */ | 29 | */ |
| 30 | #include <srs_core.hpp> | 30 | #include <srs_core.hpp> |
| 31 | 31 | ||
| 32 | -#ifdef SRS_AUTO_HTTP_PARSER | ||
| 33 | - | ||
| 34 | -#include <map> | ||
| 35 | -#include <string> | ||
| 36 | -#include <vector> | ||
| 37 | - | ||
| 38 | -#include <http_parser.h> | ||
| 39 | - | ||
| 40 | -#include <srs_app_st.hpp> | ||
| 41 | -#include <srs_http_stack.hpp> | ||
| 42 | - | ||
| 43 | -class SrsRequest; | ||
| 44 | -class SrsStSocket; | ||
| 45 | -class SrsHttpMessage; | ||
| 46 | -class SrsFastBuffer; | ||
| 47 | -class SrsHttpUri; | ||
| 48 | -class SrsConnection; | ||
| 49 | - | ||
| 50 | -/** | ||
| 51 | - * response writer use st socket | ||
| 52 | - */ | ||
| 53 | -class SrsHttpResponseWriter : public ISrsHttpResponseWriter | ||
| 54 | -{ | ||
| 55 | -private: | ||
| 56 | - SrsStSocket* skt; | ||
| 57 | - SrsHttpHeader* hdr; | ||
| 58 | -private: | ||
| 59 | - // reply header has been (logically) written | ||
| 60 | - bool header_wrote; | ||
| 61 | - // status code passed to WriteHeader | ||
| 62 | - int status; | ||
| 63 | -private: | ||
| 64 | - // explicitly-declared Content-Length; or -1 | ||
| 65 | - int64_t content_length; | ||
| 66 | - // number of bytes written in body | ||
| 67 | - int64_t written; | ||
| 68 | -private: | ||
| 69 | - // wroteHeader tells whether the header's been written to "the | ||
| 70 | - // wire" (or rather: w.conn.buf). this is unlike | ||
| 71 | - // (*response).wroteHeader, which tells only whether it was | ||
| 72 | - // logically written. | ||
| 73 | - bool header_sent; | ||
| 74 | -public: | ||
| 75 | - SrsHttpResponseWriter(SrsStSocket* io); | ||
| 76 | - virtual ~SrsHttpResponseWriter(); | ||
| 77 | -public: | ||
| 78 | - virtual int final_request(); | ||
| 79 | - virtual SrsHttpHeader* header(); | ||
| 80 | - virtual int write(char* data, int size); | ||
| 81 | - virtual void write_header(int code); | ||
| 82 | - virtual int send_header(char* data, int size); | ||
| 83 | -}; | ||
| 84 | - | ||
| 85 | -/** | ||
| 86 | - * response reader use st socket. | ||
| 87 | - */ | ||
| 88 | -class SrsHttpResponseReader : virtual public ISrsHttpResponseReader | ||
| 89 | -{ | ||
| 90 | -private: | ||
| 91 | - SrsStSocket* skt; | ||
| 92 | - SrsHttpMessage* owner; | ||
| 93 | - SrsFastBuffer* buffer; | ||
| 94 | - bool is_eof; | ||
| 95 | - // the left bytes in chunk. | ||
| 96 | - int nb_left_chunk; | ||
| 97 | - // the number of bytes of current chunk. | ||
| 98 | - int nb_chunk; | ||
| 99 | - // already read total bytes. | ||
| 100 | - int64_t nb_total_read; | ||
| 101 | -public: | ||
| 102 | - SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io); | ||
| 103 | - virtual ~SrsHttpResponseReader(); | ||
| 104 | -public: | ||
| 105 | - /** | ||
| 106 | - * initialize the response reader with buffer. | ||
| 107 | - */ | ||
| 108 | - virtual int initialize(SrsFastBuffer* buffer); | ||
| 109 | - // interface ISrsHttpResponseReader | ||
| 110 | -public: | ||
| 111 | - virtual bool eof(); | ||
| 112 | - virtual int read(char* data, int nb_data, int* nb_read); | ||
| 113 | -private: | ||
| 114 | - virtual int read_chunked(char* data, int nb_data, int* nb_read); | ||
| 115 | - virtual int read_specified(char* data, int nb_data, int* nb_read); | ||
| 116 | -}; | ||
| 117 | - | ||
| 118 | -// for http header. | ||
| 119 | -typedef std::pair<std::string, std::string> SrsHttpHeaderField; | ||
| 120 | - | ||
| 121 | -// A Request represents an HTTP request received by a server | ||
| 122 | -// or to be sent by a client. | ||
| 123 | -// | ||
| 124 | -// The field semantics differ slightly between client and server | ||
| 125 | -// usage. In addition to the notes on the fields below, see the | ||
| 126 | -// documentation for Request.Write and RoundTripper. | ||
| 127 | -/** | ||
| 128 | - * the http message, request or response. | ||
| 129 | - */ | ||
| 130 | -class SrsHttpMessage : public ISrsHttpMessage | ||
| 131 | -{ | ||
| 132 | -private: | ||
| 133 | - /** | ||
| 134 | - * parsed url. | ||
| 135 | - */ | ||
| 136 | - std::string _url; | ||
| 137 | - /** | ||
| 138 | - * the extension of file, for example, .flv | ||
| 139 | - */ | ||
| 140 | - std::string _ext; | ||
| 141 | - /** | ||
| 142 | - * parsed http header. | ||
| 143 | - */ | ||
| 144 | - http_parser _header; | ||
| 145 | - /** | ||
| 146 | - * body object, reader object. | ||
| 147 | - * @remark, user can get body in string by get_body(). | ||
| 148 | - */ | ||
| 149 | - SrsHttpResponseReader* _body; | ||
| 150 | - /** | ||
| 151 | - * whether the body is chunked. | ||
| 152 | - */ | ||
| 153 | - bool chunked; | ||
| 154 | - /** | ||
| 155 | - * whether the request indicates should keep alive | ||
| 156 | - * for the http connection. | ||
| 157 | - */ | ||
| 158 | - bool keep_alive; | ||
| 159 | - /** | ||
| 160 | - * uri parser | ||
| 161 | - */ | ||
| 162 | - SrsHttpUri* _uri; | ||
| 163 | - /** | ||
| 164 | - * use a buffer to read and send ts file. | ||
| 165 | - */ | ||
| 166 | - // TODO: FIXME: remove it. | ||
| 167 | - char* _http_ts_send_buffer; | ||
| 168 | - // http headers | ||
| 169 | - std::vector<SrsHttpHeaderField> _headers; | ||
| 170 | - // the query map | ||
| 171 | - std::map<std::string, std::string> _query; | ||
| 172 | - // the transport connection, can be NULL. | ||
| 173 | - SrsConnection* conn; | ||
| 174 | -public: | ||
| 175 | - SrsHttpMessage(SrsStSocket* io, SrsConnection* c); | ||
| 176 | - virtual ~SrsHttpMessage(); | ||
| 177 | -public: | ||
| 178 | - /** | ||
| 179 | - * set the original messages, then update the message. | ||
| 180 | - */ | ||
| 181 | - virtual int update(std::string url, http_parser* header, | ||
| 182 | - SrsFastBuffer* body, std::vector<SrsHttpHeaderField>& headers | ||
| 183 | - ); | ||
| 184 | -private: | ||
| 185 | - virtual SrsConnection* connection(); | ||
| 186 | -public: | ||
| 187 | - virtual u_int8_t method(); | ||
| 188 | - virtual u_int16_t status_code(); | ||
| 189 | - /** | ||
| 190 | - * method helpers. | ||
| 191 | - */ | ||
| 192 | - virtual std::string method_str(); | ||
| 193 | - virtual bool is_http_get(); | ||
| 194 | - virtual bool is_http_put(); | ||
| 195 | - virtual bool is_http_post(); | ||
| 196 | - virtual bool is_http_delete(); | ||
| 197 | - virtual bool is_http_options(); | ||
| 198 | - /** | ||
| 199 | - * whether body is chunked encoding, for reader only. | ||
| 200 | - */ | ||
| 201 | - virtual bool is_chunked(); | ||
| 202 | - /** | ||
| 203 | - * whether should keep the connection alive. | ||
| 204 | - */ | ||
| 205 | - virtual bool is_keep_alive(); | ||
| 206 | - /** | ||
| 207 | - * the uri contains the host and path. | ||
| 208 | - */ | ||
| 209 | - virtual std::string uri(); | ||
| 210 | - /** | ||
| 211 | - * the url maybe the path. | ||
| 212 | - */ | ||
| 213 | - virtual std::string url(); | ||
| 214 | - virtual std::string host(); | ||
| 215 | - virtual std::string path(); | ||
| 216 | - virtual std::string ext(); | ||
| 217 | -public: | ||
| 218 | - /** | ||
| 219 | - * read body to string. | ||
| 220 | - * @remark for small http body. | ||
| 221 | - */ | ||
| 222 | - virtual int body_read_all(std::string& body); | ||
| 223 | - /** | ||
| 224 | - * get the body reader, to read one by one. | ||
| 225 | - * @remark when body is very large, or chunked, use this. | ||
| 226 | - */ | ||
| 227 | - virtual ISrsHttpResponseReader* body_reader(); | ||
| 228 | - /** | ||
| 229 | - * the content length, -1 for chunked or not set. | ||
| 230 | - */ | ||
| 231 | - virtual int64_t content_length(); | ||
| 232 | - /** | ||
| 233 | - * get the param in query string, | ||
| 234 | - * for instance, query is "start=100&end=200", | ||
| 235 | - * then query_get("start") is "100", and query_get("end") is "200" | ||
| 236 | - */ | ||
| 237 | - virtual std::string query_get(std::string key); | ||
| 238 | - /** | ||
| 239 | - * get the headers. | ||
| 240 | - */ | ||
| 241 | - virtual int request_header_count(); | ||
| 242 | - virtual std::string request_header_key_at(int index); | ||
| 243 | - virtual std::string request_header_value_at(int index); | ||
| 244 | - virtual std::string get_request_header(std::string name); | ||
| 245 | -public: | ||
| 246 | - /** | ||
| 247 | - * convert the http message to a request. | ||
| 248 | - * @remark user must free the return request. | ||
| 249 | - */ | ||
| 250 | - virtual SrsRequest* to_request(std::string vhost); | ||
| 251 | -}; | ||
| 252 | - | ||
| 253 | -/** | ||
| 254 | -* wrapper for http-parser, | ||
| 255 | -* provides HTTP message originted service. | ||
| 256 | -*/ | ||
| 257 | -class SrsHttpParser | ||
| 258 | -{ | ||
| 259 | -private: | ||
| 260 | - http_parser_settings settings; | ||
| 261 | - http_parser parser; | ||
| 262 | - // the global parse buffer. | ||
| 263 | - SrsFastBuffer* buffer; | ||
| 264 | -private: | ||
| 265 | - // http parse data, reset before parse message. | ||
| 266 | - bool expect_field_name; | ||
| 267 | - std::string field_name; | ||
| 268 | - std::string field_value; | ||
| 269 | - SrsHttpParseState state; | ||
| 270 | - http_parser header; | ||
| 271 | - std::string url; | ||
| 272 | - std::vector<SrsHttpHeaderField> headers; | ||
| 273 | - int header_parsed; | ||
| 274 | -public: | ||
| 275 | - SrsHttpParser(); | ||
| 276 | - virtual ~SrsHttpParser(); | ||
| 277 | -public: | ||
| 278 | - /** | ||
| 279 | - * initialize the http parser with specified type, | ||
| 280 | - * one parser can only parse request or response messages. | ||
| 281 | - */ | ||
| 282 | - virtual int initialize(enum http_parser_type type); | ||
| 283 | - /** | ||
| 284 | - * always parse a http message, | ||
| 285 | - * that is, the *ppmsg always NOT-NULL when return success. | ||
| 286 | - * or error and *ppmsg must be NULL. | ||
| 287 | - * @remark, if success, *ppmsg always NOT-NULL, *ppmsg always is_complete(). | ||
| 288 | - */ | ||
| 289 | - virtual int parse_message(SrsStSocket* skt, SrsConnection* conn, ISrsHttpMessage** ppmsg); | ||
| 290 | -private: | ||
| 291 | - /** | ||
| 292 | - * parse the HTTP message to member field: msg. | ||
| 293 | - */ | ||
| 294 | - virtual int parse_message_imp(SrsStSocket* skt); | ||
| 295 | -private: | ||
| 296 | - static int on_message_begin(http_parser* parser); | ||
| 297 | - static int on_headers_complete(http_parser* parser); | ||
| 298 | - static int on_message_complete(http_parser* parser); | ||
| 299 | - static int on_url(http_parser* parser, const char* at, size_t length); | ||
| 300 | - static int on_header_field(http_parser* parser, const char* at, size_t length); | ||
| 301 | - static int on_header_value(http_parser* parser, const char* at, size_t length); | ||
| 302 | - static int on_body(http_parser* parser, const char* at, size_t length); | ||
| 303 | -}; | ||
| 304 | - | ||
| 305 | -/** | ||
| 306 | -* used to resolve the http uri. | ||
| 307 | -*/ | ||
| 308 | -class SrsHttpUri | ||
| 309 | -{ | ||
| 310 | -private: | ||
| 311 | - std::string url; | ||
| 312 | - std::string schema; | ||
| 313 | - std::string host; | ||
| 314 | - int port; | ||
| 315 | - std::string path; | ||
| 316 | - std::string query; | ||
| 317 | -public: | ||
| 318 | - SrsHttpUri(); | ||
| 319 | - virtual ~SrsHttpUri(); | ||
| 320 | -public: | ||
| 321 | - /** | ||
| 322 | - * initialize the http uri. | ||
| 323 | - */ | ||
| 324 | - virtual int initialize(std::string _url); | ||
| 325 | -public: | ||
| 326 | - virtual const char* get_url(); | ||
| 327 | - virtual const char* get_schema(); | ||
| 328 | - virtual const char* get_host(); | ||
| 329 | - virtual int get_port(); | ||
| 330 | - virtual const char* get_path(); | ||
| 331 | - virtual const char* get_query(); | ||
| 332 | -private: | ||
| 333 | - /** | ||
| 334 | - * get the parsed url field. | ||
| 335 | - * @return return empty string if not set. | ||
| 336 | - */ | ||
| 337 | - virtual std::string get_uri_field(std::string uri, http_parser_url* hp_u, http_parser_url_fields field); | ||
| 338 | -}; | ||
| 339 | - | ||
| 340 | -#endif | ||
| 341 | - | ||
| 342 | #endif | 32 | #endif |
| @@ -39,6 +39,7 @@ using namespace std; | @@ -39,6 +39,7 @@ using namespace std; | ||
| 39 | #include <srs_rtmp_sdk.hpp> | 39 | #include <srs_rtmp_sdk.hpp> |
| 40 | #include <srs_app_dvr.hpp> | 40 | #include <srs_app_dvr.hpp> |
| 41 | #include <srs_app_config.hpp> | 41 | #include <srs_app_config.hpp> |
| 42 | +#include <srs_app_http_conn.hpp> | ||
| 42 | 43 | ||
| 43 | SrsGoApiRoot::SrsGoApiRoot() | 44 | SrsGoApiRoot::SrsGoApiRoot() |
| 44 | { | 45 | { |
| @@ -39,7 +39,7 @@ class SrsHttpHandler; | @@ -39,7 +39,7 @@ class SrsHttpHandler; | ||
| 39 | 39 | ||
| 40 | #include <srs_app_st.hpp> | 40 | #include <srs_app_st.hpp> |
| 41 | #include <srs_app_conn.hpp> | 41 | #include <srs_app_conn.hpp> |
| 42 | -#include <srs_app_http.hpp> | 42 | +#include <srs_http_stack.hpp> |
| 43 | 43 | ||
| 44 | // for http root. | 44 | // for http root. |
| 45 | class SrsGoApiRoot : public ISrsHttpHandler | 45 | class SrsGoApiRoot : public ISrsHttpHandler |
| @@ -36,6 +36,7 @@ using namespace std; | @@ -36,6 +36,7 @@ using namespace std; | ||
| 36 | #include <srs_kernel_utility.hpp> | 36 | #include <srs_kernel_utility.hpp> |
| 37 | #include <srs_app_utility.hpp> | 37 | #include <srs_app_utility.hpp> |
| 38 | #include <srs_core_autofree.hpp> | 38 | #include <srs_core_autofree.hpp> |
| 39 | +#include <srs_app_http_conn.hpp> | ||
| 39 | 40 | ||
| 40 | SrsHttpClient::SrsHttpClient() | 41 | SrsHttpClient::SrsHttpClient() |
| 41 | { | 42 | { |
| @@ -23,7 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -23,7 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | 23 | ||
| 24 | #include <srs_app_http_conn.hpp> | 24 | #include <srs_app_http_conn.hpp> |
| 25 | 25 | ||
| 26 | -#ifdef SRS_AUTO_HTTP_SERVER | 26 | +#if defined(SRS_AUTO_HTTP_PARSER) || defined(SRS_AUTO_HTTP_SERVER) |
| 27 | 27 | ||
| 28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
| 29 | #include <sys/stat.h> | 29 | #include <sys/stat.h> |
| @@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 33 | #include <sstream> | 33 | #include <sstream> |
| 34 | using namespace std; | 34 | using namespace std; |
| 35 | 35 | ||
| 36 | +#include <srs_rtmp_buffer.hpp> | ||
| 37 | +#include <srs_rtmp_utility.hpp> | ||
| 36 | #include <srs_kernel_log.hpp> | 38 | #include <srs_kernel_log.hpp> |
| 37 | #include <srs_kernel_error.hpp> | 39 | #include <srs_kernel_error.hpp> |
| 38 | #include <srs_app_st_socket.hpp> | 40 | #include <srs_app_st_socket.hpp> |
| @@ -51,6 +53,959 @@ using namespace std; | @@ -51,6 +53,959 @@ using namespace std; | ||
| 51 | #include <srs_app_source.hpp> | 53 | #include <srs_app_source.hpp> |
| 52 | #include <srs_app_server.hpp> | 54 | #include <srs_app_server.hpp> |
| 53 | 55 | ||
| 56 | +#endif | ||
| 57 | + | ||
| 58 | +#ifdef SRS_AUTO_HTTP_PARSER | ||
| 59 | + | ||
| 60 | +SrsHttpResponseWriter::SrsHttpResponseWriter(SrsStSocket* io) | ||
| 61 | +{ | ||
| 62 | + skt = io; | ||
| 63 | + hdr = new SrsHttpHeader(); | ||
| 64 | + header_wrote = false; | ||
| 65 | + status = SRS_CONSTS_HTTP_OK; | ||
| 66 | + content_length = -1; | ||
| 67 | + written = 0; | ||
| 68 | + header_sent = false; | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +SrsHttpResponseWriter::~SrsHttpResponseWriter() | ||
| 72 | +{ | ||
| 73 | + srs_freep(hdr); | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +int SrsHttpResponseWriter::final_request() | ||
| 77 | +{ | ||
| 78 | + // complete the chunked encoding. | ||
| 79 | + if (content_length == -1) { | ||
| 80 | + std::stringstream ss; | ||
| 81 | + ss << 0 << SRS_HTTP_CRLF << SRS_HTTP_CRLF; | ||
| 82 | + std::string ch = ss.str(); | ||
| 83 | + return skt->write((void*)ch.data(), (int)ch.length(), NULL); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + // flush when send with content length | ||
| 87 | + return write(NULL, 0); | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +SrsHttpHeader* SrsHttpResponseWriter::header() | ||
| 91 | +{ | ||
| 92 | + return hdr; | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +int SrsHttpResponseWriter::write(char* data, int size) | ||
| 96 | +{ | ||
| 97 | + int ret = ERROR_SUCCESS; | ||
| 98 | + | ||
| 99 | + if (!header_wrote) { | ||
| 100 | + write_header(SRS_CONSTS_HTTP_OK); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + written += size; | ||
| 104 | + if (content_length != -1 && written > content_length) { | ||
| 105 | + ret = ERROR_HTTP_CONTENT_LENGTH; | ||
| 106 | + srs_error("http: exceed content length. ret=%d", ret); | ||
| 107 | + return ret; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + if ((ret = send_header(data, size)) != ERROR_SUCCESS) { | ||
| 111 | + srs_error("http: send header failed. ret=%d", ret); | ||
| 112 | + return ret; | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + // ignore NULL content. | ||
| 116 | + if (!data) { | ||
| 117 | + return ret; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + // directly send with content length | ||
| 121 | + if (content_length != -1) { | ||
| 122 | + return skt->write((void*)data, size, NULL); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + // send in chunked encoding. | ||
| 126 | + std::stringstream ss; | ||
| 127 | + ss << hex << size << SRS_HTTP_CRLF; | ||
| 128 | + std::string ch = ss.str(); | ||
| 129 | + if ((ret = skt->write((void*)ch.data(), (int)ch.length(), NULL)) != ERROR_SUCCESS) { | ||
| 130 | + return ret; | ||
| 131 | + } | ||
| 132 | + if ((ret = skt->write((void*)data, size, NULL)) != ERROR_SUCCESS) { | ||
| 133 | + return ret; | ||
| 134 | + } | ||
| 135 | + if ((ret = skt->write((void*)SRS_HTTP_CRLF, 2, NULL)) != ERROR_SUCCESS) { | ||
| 136 | + return ret; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + return ret; | ||
| 140 | +} | ||
| 141 | + | ||
| 142 | +void SrsHttpResponseWriter::write_header(int code) | ||
| 143 | +{ | ||
| 144 | + if (header_wrote) { | ||
| 145 | + srs_warn("http: multiple write_header calls, code=%d", code); | ||
| 146 | + return; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + header_wrote = true; | ||
| 150 | + status = code; | ||
| 151 | + | ||
| 152 | + // parse the content length from header. | ||
| 153 | + content_length = hdr->content_length(); | ||
| 154 | +} | ||
| 155 | + | ||
| 156 | +int SrsHttpResponseWriter::send_header(char* data, int size) | ||
| 157 | +{ | ||
| 158 | + int ret = ERROR_SUCCESS; | ||
| 159 | + | ||
| 160 | + if (header_sent) { | ||
| 161 | + return ret; | ||
| 162 | + } | ||
| 163 | + header_sent = true; | ||
| 164 | + | ||
| 165 | + std::stringstream ss; | ||
| 166 | + | ||
| 167 | + // status_line | ||
| 168 | + ss << "HTTP/1.1 " << status << " " | ||
| 169 | + << srs_generate_http_status_text(status) << SRS_HTTP_CRLF; | ||
| 170 | + | ||
| 171 | + // detect content type | ||
| 172 | + if (srs_go_http_body_allowd(status)) { | ||
| 173 | + if (hdr->content_type().empty()) { | ||
| 174 | + hdr->set_content_type(srs_go_http_detect(data, size)); | ||
| 175 | + } | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + // set server if not set. | ||
| 179 | + if (hdr->get("Server").empty()) { | ||
| 180 | + hdr->set("Server", RTMP_SIG_SRS_KEY"/"RTMP_SIG_SRS_VERSION); | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + // chunked encoding | ||
| 184 | + if (content_length == -1) { | ||
| 185 | + hdr->set("Transfer-Encoding", "chunked"); | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + // keep alive to make vlc happy. | ||
| 189 | + hdr->set("Connection", "Keep-Alive"); | ||
| 190 | + | ||
| 191 | + // write headers | ||
| 192 | + hdr->write(ss); | ||
| 193 | + | ||
| 194 | + // header_eof | ||
| 195 | + ss << SRS_HTTP_CRLF; | ||
| 196 | + | ||
| 197 | + std::string buf = ss.str(); | ||
| 198 | + return skt->write((void*)buf.c_str(), buf.length(), NULL); | ||
| 199 | +} | ||
| 200 | + | ||
| 201 | +SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io) | ||
| 202 | +{ | ||
| 203 | + skt = io; | ||
| 204 | + owner = msg; | ||
| 205 | + is_eof = false; | ||
| 206 | + nb_total_read = 0; | ||
| 207 | + nb_left_chunk = 0; | ||
| 208 | + buffer = NULL; | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +SrsHttpResponseReader::~SrsHttpResponseReader() | ||
| 212 | +{ | ||
| 213 | +} | ||
| 214 | + | ||
| 215 | +int SrsHttpResponseReader::initialize(SrsFastBuffer* body) | ||
| 216 | +{ | ||
| 217 | + int ret = ERROR_SUCCESS; | ||
| 218 | + | ||
| 219 | + nb_chunk = 0; | ||
| 220 | + nb_left_chunk = 0; | ||
| 221 | + nb_total_read = 0; | ||
| 222 | + buffer = body; | ||
| 223 | + | ||
| 224 | + return ret; | ||
| 225 | +} | ||
| 226 | + | ||
| 227 | +bool SrsHttpResponseReader::eof() | ||
| 228 | +{ | ||
| 229 | + return is_eof; | ||
| 230 | +} | ||
| 231 | + | ||
| 232 | +int SrsHttpResponseReader::read(char* data, int nb_data, int* nb_read) | ||
| 233 | +{ | ||
| 234 | + int ret = ERROR_SUCCESS; | ||
| 235 | + | ||
| 236 | + if (is_eof) { | ||
| 237 | + ret = ERROR_HTTP_RESPONSE_EOF; | ||
| 238 | + srs_error("http: response EOF. ret=%d", ret); | ||
| 239 | + return ret; | ||
| 240 | + } | ||
| 241 | + | ||
| 242 | + // chunked encoding. | ||
| 243 | + if (owner->is_chunked()) { | ||
| 244 | + return read_chunked(data, nb_data, nb_read); | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + // read by specified content-length | ||
| 248 | + int max = (int)owner->content_length() - (int)nb_total_read; | ||
| 249 | + if (max <= 0) { | ||
| 250 | + is_eof = true; | ||
| 251 | + return ret; | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + // change the max to read. | ||
| 255 | + nb_data = srs_min(nb_data, max); | ||
| 256 | + return read_specified(data, nb_data, nb_read); | ||
| 257 | +} | ||
| 258 | + | ||
| 259 | +int SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb_read) | ||
| 260 | +{ | ||
| 261 | + int ret = ERROR_SUCCESS; | ||
| 262 | + | ||
| 263 | + // when no bytes left in chunk, | ||
| 264 | + // parse the chunk length first. | ||
| 265 | + if (nb_left_chunk <= 0) { | ||
| 266 | + char* at = NULL; | ||
| 267 | + int length = 0; | ||
| 268 | + while (!at) { | ||
| 269 | + // find the CRLF of chunk header end. | ||
| 270 | + char* start = buffer->bytes(); | ||
| 271 | + char* end = start + buffer->size(); | ||
| 272 | + for (char* p = start; p < end - 1; p++) { | ||
| 273 | + if (p[0] == SRS_HTTP_CR && p[1] == SRS_HTTP_LF) { | ||
| 274 | + // invalid chunk, ignore. | ||
| 275 | + if (p == start) { | ||
| 276 | + ret = ERROR_HTTP_INVALID_CHUNK_HEADER; | ||
| 277 | + srs_error("chunk header start with CRLF. ret=%d", ret); | ||
| 278 | + return ret; | ||
| 279 | + } | ||
| 280 | + length = (int)(p - start + 2); | ||
| 281 | + at = buffer->read_slice(length); | ||
| 282 | + break; | ||
| 283 | + } | ||
| 284 | + } | ||
| 285 | + | ||
| 286 | + // got at, ok. | ||
| 287 | + if (at) { | ||
| 288 | + break; | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + // when empty, only grow 1bytes, but the buffer will cache more. | ||
| 292 | + if ((ret = buffer->grow(skt, buffer->size() + 1)) != ERROR_SUCCESS) { | ||
| 293 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 294 | + srs_error("read body from server failed. ret=%d", ret); | ||
| 295 | + } | ||
| 296 | + return ret; | ||
| 297 | + } | ||
| 298 | + } | ||
| 299 | + srs_assert(length >= 3); | ||
| 300 | + | ||
| 301 | + // it's ok to set the pos and pos+1 to NULL. | ||
| 302 | + at[length - 1] = 0; | ||
| 303 | + at[length - 2] = 0; | ||
| 304 | + | ||
| 305 | + // size is the bytes size, excludes the chunk header and end CRLF. | ||
| 306 | + int ilength = (int)::strtol(at, NULL, 16); | ||
| 307 | + if (ilength < 0) { | ||
| 308 | + ret = ERROR_HTTP_INVALID_CHUNK_HEADER; | ||
| 309 | + srs_error("chunk header negative, length=%d. ret=%d", ilength, ret); | ||
| 310 | + return ret; | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + // all bytes in chunk is left now. | ||
| 314 | + nb_chunk = nb_left_chunk = ilength; | ||
| 315 | + } | ||
| 316 | + | ||
| 317 | + if (nb_chunk <= 0) { | ||
| 318 | + // for the last chunk, eof. | ||
| 319 | + is_eof = true; | ||
| 320 | + } else { | ||
| 321 | + // for not the last chunk, there must always exists bytes. | ||
| 322 | + // left bytes in chunk, read some. | ||
| 323 | + srs_assert(nb_left_chunk); | ||
| 324 | + | ||
| 325 | + int nb_bytes = srs_min(nb_left_chunk, nb_data); | ||
| 326 | + ret = read_specified(data, nb_bytes, &nb_bytes); | ||
| 327 | + | ||
| 328 | + // the nb_bytes used for output already read size of bytes. | ||
| 329 | + if (nb_read) { | ||
| 330 | + *nb_read = nb_bytes; | ||
| 331 | + } | ||
| 332 | + nb_left_chunk -= nb_bytes; | ||
| 333 | + srs_info("http: read %d bytes of chunk", nb_bytes); | ||
| 334 | + | ||
| 335 | + // error or still left bytes in chunk, ignore and read in future. | ||
| 336 | + if (nb_left_chunk > 0 || (ret != ERROR_SUCCESS)) { | ||
| 337 | + return ret; | ||
| 338 | + } | ||
| 339 | + srs_info("http: read total chunk %dB", nb_chunk); | ||
| 340 | + } | ||
| 341 | + | ||
| 342 | + // for both the last or not, the CRLF of chunk payload end. | ||
| 343 | + if ((ret = buffer->grow(skt, 2)) != ERROR_SUCCESS) { | ||
| 344 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 345 | + srs_error("read EOF of chunk from server failed. ret=%d", ret); | ||
| 346 | + } | ||
| 347 | + return ret; | ||
| 348 | + } | ||
| 349 | + buffer->read_slice(2); | ||
| 350 | + | ||
| 351 | + return ret; | ||
| 352 | +} | ||
| 353 | + | ||
| 354 | +int SrsHttpResponseReader::read_specified(char* data, int nb_data, int* nb_read) | ||
| 355 | +{ | ||
| 356 | + int ret = ERROR_SUCCESS; | ||
| 357 | + | ||
| 358 | + if (buffer->size() <= 0) { | ||
| 359 | + // when empty, only grow 1bytes, but the buffer will cache more. | ||
| 360 | + if ((ret = buffer->grow(skt, 1)) != ERROR_SUCCESS) { | ||
| 361 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 362 | + srs_error("read body from server failed. ret=%d", ret); | ||
| 363 | + } | ||
| 364 | + return ret; | ||
| 365 | + } | ||
| 366 | + } | ||
| 367 | + | ||
| 368 | + int nb_bytes = srs_min(nb_data, buffer->size()); | ||
| 369 | + | ||
| 370 | + // read data to buffer. | ||
| 371 | + srs_assert(nb_bytes); | ||
| 372 | + char* p = buffer->read_slice(nb_bytes); | ||
| 373 | + memcpy(data, p, nb_bytes); | ||
| 374 | + if (nb_read) { | ||
| 375 | + *nb_read = nb_bytes; | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + // increase the total read to determine whether EOF. | ||
| 379 | + nb_total_read += nb_bytes; | ||
| 380 | + | ||
| 381 | + // for not chunked | ||
| 382 | + if (!owner->is_chunked()) { | ||
| 383 | + // when read completed, eof. | ||
| 384 | + if (nb_total_read >= (int)owner->content_length()) { | ||
| 385 | + is_eof = true; | ||
| 386 | + } | ||
| 387 | + } | ||
| 388 | + | ||
| 389 | + return ret; | ||
| 390 | +} | ||
| 391 | + | ||
| 392 | +SrsHttpMessage::SrsHttpMessage(SrsStSocket* io, SrsConnection* c) : ISrsHttpMessage() | ||
| 393 | +{ | ||
| 394 | + conn = c; | ||
| 395 | + chunked = false; | ||
| 396 | + keep_alive = true; | ||
| 397 | + _uri = new SrsHttpUri(); | ||
| 398 | + _body = new SrsHttpResponseReader(this, io); | ||
| 399 | + _http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE]; | ||
| 400 | +} | ||
| 401 | + | ||
| 402 | +SrsHttpMessage::~SrsHttpMessage() | ||
| 403 | +{ | ||
| 404 | + srs_freep(_body); | ||
| 405 | + srs_freep(_uri); | ||
| 406 | + srs_freep(_http_ts_send_buffer); | ||
| 407 | +} | ||
| 408 | + | ||
| 409 | +int SrsHttpMessage::update(string url, http_parser* header, SrsFastBuffer* body, vector<SrsHttpHeaderField>& headers) | ||
| 410 | +{ | ||
| 411 | + int ret = ERROR_SUCCESS; | ||
| 412 | + | ||
| 413 | + _url = url; | ||
| 414 | + _header = *header; | ||
| 415 | + _headers = headers; | ||
| 416 | + | ||
| 417 | + // whether chunked. | ||
| 418 | + std::string transfer_encoding = get_request_header("Transfer-Encoding"); | ||
| 419 | + chunked = (transfer_encoding == "chunked"); | ||
| 420 | + | ||
| 421 | + // whether keep alive. | ||
| 422 | + keep_alive = http_should_keep_alive(header); | ||
| 423 | + | ||
| 424 | + // set the buffer. | ||
| 425 | + if ((ret = _body->initialize(body)) != ERROR_SUCCESS) { | ||
| 426 | + return ret; | ||
| 427 | + } | ||
| 428 | + | ||
| 429 | + // parse uri from url. | ||
| 430 | + std::string host = get_request_header("Host"); | ||
| 431 | + | ||
| 432 | + // donot parse the empty host for uri, | ||
| 433 | + // for example, the response contains no host, | ||
| 434 | + // ignore it is ok. | ||
| 435 | + if (host.empty()) { | ||
| 436 | + return ret; | ||
| 437 | + } | ||
| 438 | + | ||
| 439 | + // parse uri to schema/server:port/path?query | ||
| 440 | + std::string uri = "http://" + host + _url; | ||
| 441 | + if ((ret = _uri->initialize(uri)) != ERROR_SUCCESS) { | ||
| 442 | + return ret; | ||
| 443 | + } | ||
| 444 | + | ||
| 445 | + // must format as key=value&...&keyN=valueN | ||
| 446 | + std::string q = _uri->get_query(); | ||
| 447 | + size_t pos = string::npos; | ||
| 448 | + while (!q.empty()) { | ||
| 449 | + std::string k = q; | ||
| 450 | + if ((pos = q.find("=")) != string::npos) { | ||
| 451 | + k = q.substr(0, pos); | ||
| 452 | + q = q.substr(pos + 1); | ||
| 453 | + } else { | ||
| 454 | + q = ""; | ||
| 455 | + } | ||
| 456 | + | ||
| 457 | + std::string v = q; | ||
| 458 | + if ((pos = q.find("&")) != string::npos) { | ||
| 459 | + v = q.substr(0, pos); | ||
| 460 | + q = q.substr(pos + 1); | ||
| 461 | + } else { | ||
| 462 | + q = ""; | ||
| 463 | + } | ||
| 464 | + | ||
| 465 | + _query[k] = v; | ||
| 466 | + } | ||
| 467 | + | ||
| 468 | + // parse ext. | ||
| 469 | + _ext = _uri->get_path(); | ||
| 470 | + if ((pos = _ext.rfind(".")) != string::npos) { | ||
| 471 | + _ext = _ext.substr(pos); | ||
| 472 | + } else { | ||
| 473 | + _ext = ""; | ||
| 474 | + } | ||
| 475 | + | ||
| 476 | + return ret; | ||
| 477 | +} | ||
| 478 | + | ||
| 479 | +SrsConnection* SrsHttpMessage::connection() | ||
| 480 | +{ | ||
| 481 | + return conn; | ||
| 482 | +} | ||
| 483 | + | ||
| 484 | +u_int8_t SrsHttpMessage::method() | ||
| 485 | +{ | ||
| 486 | + return (u_int8_t)_header.method; | ||
| 487 | +} | ||
| 488 | + | ||
| 489 | +u_int16_t SrsHttpMessage::status_code() | ||
| 490 | +{ | ||
| 491 | + return (u_int16_t)_header.status_code; | ||
| 492 | +} | ||
| 493 | + | ||
| 494 | +string SrsHttpMessage::method_str() | ||
| 495 | +{ | ||
| 496 | + if (is_http_get()) { | ||
| 497 | + return "GET"; | ||
| 498 | + } | ||
| 499 | + if (is_http_put()) { | ||
| 500 | + return "PUT"; | ||
| 501 | + } | ||
| 502 | + if (is_http_post()) { | ||
| 503 | + return "POST"; | ||
| 504 | + } | ||
| 505 | + if (is_http_delete()) { | ||
| 506 | + return "DELETE"; | ||
| 507 | + } | ||
| 508 | + if (is_http_options()) { | ||
| 509 | + return "OPTIONS"; | ||
| 510 | + } | ||
| 511 | + | ||
| 512 | + return "OTHER"; | ||
| 513 | +} | ||
| 514 | + | ||
| 515 | +bool SrsHttpMessage::is_http_get() | ||
| 516 | +{ | ||
| 517 | + return _header.method == SRS_CONSTS_HTTP_GET; | ||
| 518 | +} | ||
| 519 | + | ||
| 520 | +bool SrsHttpMessage::is_http_put() | ||
| 521 | +{ | ||
| 522 | + return _header.method == SRS_CONSTS_HTTP_PUT; | ||
| 523 | +} | ||
| 524 | + | ||
| 525 | +bool SrsHttpMessage::is_http_post() | ||
| 526 | +{ | ||
| 527 | + return _header.method == SRS_CONSTS_HTTP_POST; | ||
| 528 | +} | ||
| 529 | + | ||
| 530 | +bool SrsHttpMessage::is_http_delete() | ||
| 531 | +{ | ||
| 532 | + return _header.method == SRS_CONSTS_HTTP_DELETE; | ||
| 533 | +} | ||
| 534 | + | ||
| 535 | +bool SrsHttpMessage::is_http_options() | ||
| 536 | +{ | ||
| 537 | + return _header.method == SRS_CONSTS_HTTP_OPTIONS; | ||
| 538 | +} | ||
| 539 | + | ||
| 540 | +bool SrsHttpMessage::is_chunked() | ||
| 541 | +{ | ||
| 542 | + return chunked; | ||
| 543 | +} | ||
| 544 | + | ||
| 545 | +bool SrsHttpMessage::is_keep_alive() | ||
| 546 | +{ | ||
| 547 | + return keep_alive; | ||
| 548 | +} | ||
| 549 | + | ||
| 550 | +string SrsHttpMessage::uri() | ||
| 551 | +{ | ||
| 552 | + std::string uri = _uri->get_schema(); | ||
| 553 | + if (uri.empty()) { | ||
| 554 | + uri += "http"; | ||
| 555 | + } | ||
| 556 | + uri += "://"; | ||
| 557 | + | ||
| 558 | + uri += host(); | ||
| 559 | + uri += path(); | ||
| 560 | + return uri; | ||
| 561 | +} | ||
| 562 | + | ||
| 563 | +string SrsHttpMessage::url() | ||
| 564 | +{ | ||
| 565 | + return _uri->get_url(); | ||
| 566 | +} | ||
| 567 | + | ||
| 568 | +string SrsHttpMessage::host() | ||
| 569 | +{ | ||
| 570 | + return _uri->get_host(); | ||
| 571 | +} | ||
| 572 | + | ||
| 573 | +string SrsHttpMessage::path() | ||
| 574 | +{ | ||
| 575 | + return _uri->get_path(); | ||
| 576 | +} | ||
| 577 | + | ||
| 578 | +string SrsHttpMessage::ext() | ||
| 579 | +{ | ||
| 580 | + return _ext; | ||
| 581 | +} | ||
| 582 | + | ||
| 583 | +int SrsHttpMessage::body_read_all(string& body) | ||
| 584 | +{ | ||
| 585 | + int ret = ERROR_SUCCESS; | ||
| 586 | + | ||
| 587 | + // cache to read. | ||
| 588 | + char* buf = new char[SRS_HTTP_READ_CACHE_BYTES]; | ||
| 589 | + SrsAutoFree(char, buf); | ||
| 590 | + | ||
| 591 | + // whatever, read util EOF. | ||
| 592 | + while (!_body->eof()) { | ||
| 593 | + int nb_read = 0; | ||
| 594 | + if ((ret = _body->read(buf, SRS_HTTP_READ_CACHE_BYTES, &nb_read)) != ERROR_SUCCESS) { | ||
| 595 | + return ret; | ||
| 596 | + } | ||
| 597 | + | ||
| 598 | + if (nb_read > 0) { | ||
| 599 | + body.append(buf, nb_read); | ||
| 600 | + } | ||
| 601 | + } | ||
| 602 | + | ||
| 603 | + return ret; | ||
| 604 | +} | ||
| 605 | + | ||
| 606 | +ISrsHttpResponseReader* SrsHttpMessage::body_reader() | ||
| 607 | +{ | ||
| 608 | + return _body; | ||
| 609 | +} | ||
| 610 | + | ||
| 611 | +int64_t SrsHttpMessage::content_length() | ||
| 612 | +{ | ||
| 613 | + return _header.content_length; | ||
| 614 | +} | ||
| 615 | + | ||
| 616 | +string SrsHttpMessage::query_get(string key) | ||
| 617 | +{ | ||
| 618 | + std::string v; | ||
| 619 | + | ||
| 620 | + if (_query.find(key) != _query.end()) { | ||
| 621 | + v = _query[key]; | ||
| 622 | + } | ||
| 623 | + | ||
| 624 | + return v; | ||
| 625 | +} | ||
| 626 | + | ||
| 627 | +int SrsHttpMessage::request_header_count() | ||
| 628 | +{ | ||
| 629 | + return (int)_headers.size(); | ||
| 630 | +} | ||
| 631 | + | ||
| 632 | +string SrsHttpMessage::request_header_key_at(int index) | ||
| 633 | +{ | ||
| 634 | + srs_assert(index < request_header_count()); | ||
| 635 | + SrsHttpHeaderField item = _headers[index]; | ||
| 636 | + return item.first; | ||
| 637 | +} | ||
| 638 | + | ||
| 639 | +string SrsHttpMessage::request_header_value_at(int index) | ||
| 640 | +{ | ||
| 641 | + srs_assert(index < request_header_count()); | ||
| 642 | + SrsHttpHeaderField item = _headers[index]; | ||
| 643 | + return item.second; | ||
| 644 | +} | ||
| 645 | + | ||
| 646 | +string SrsHttpMessage::get_request_header(string name) | ||
| 647 | +{ | ||
| 648 | + std::vector<SrsHttpHeaderField>::iterator it; | ||
| 649 | + | ||
| 650 | + for (it = _headers.begin(); it != _headers.end(); ++it) { | ||
| 651 | + SrsHttpHeaderField& elem = *it; | ||
| 652 | + std::string key = elem.first; | ||
| 653 | + std::string value = elem.second; | ||
| 654 | + if (key == name) { | ||
| 655 | + return value; | ||
| 656 | + } | ||
| 657 | + } | ||
| 658 | + | ||
| 659 | + return ""; | ||
| 660 | +} | ||
| 661 | + | ||
| 662 | +SrsRequest* SrsHttpMessage::to_request(string vhost) | ||
| 663 | +{ | ||
| 664 | + SrsRequest* req = new SrsRequest(); | ||
| 665 | + | ||
| 666 | + req->app = _uri->get_path(); | ||
| 667 | + size_t pos = string::npos; | ||
| 668 | + if ((pos = req->app.rfind("/")) != string::npos) { | ||
| 669 | + req->stream = req->app.substr(pos + 1); | ||
| 670 | + req->app = req->app.substr(0, pos); | ||
| 671 | + } | ||
| 672 | + if ((pos = req->stream.rfind(".")) != string::npos) { | ||
| 673 | + req->stream = req->stream.substr(0, pos); | ||
| 674 | + } | ||
| 675 | + | ||
| 676 | + req->tcUrl = "rtmp://" + vhost + req->app; | ||
| 677 | + req->pageUrl = get_request_header("Referer"); | ||
| 678 | + req->objectEncoding = 0; | ||
| 679 | + | ||
| 680 | + srs_discovery_tc_url(req->tcUrl, | ||
| 681 | + req->schema, req->host, req->vhost, req->app, req->port, | ||
| 682 | + req->param); | ||
| 683 | + req->strip(); | ||
| 684 | + | ||
| 685 | + return req; | ||
| 686 | +} | ||
| 687 | + | ||
| 688 | +SrsHttpParser::SrsHttpParser() | ||
| 689 | +{ | ||
| 690 | + buffer = new SrsFastBuffer(); | ||
| 691 | +} | ||
| 692 | + | ||
| 693 | +SrsHttpParser::~SrsHttpParser() | ||
| 694 | +{ | ||
| 695 | + srs_freep(buffer); | ||
| 696 | +} | ||
| 697 | + | ||
| 698 | +int SrsHttpParser::initialize(enum http_parser_type type) | ||
| 699 | +{ | ||
| 700 | + int ret = ERROR_SUCCESS; | ||
| 701 | + | ||
| 702 | + memset(&settings, 0, sizeof(settings)); | ||
| 703 | + settings.on_message_begin = on_message_begin; | ||
| 704 | + settings.on_url = on_url; | ||
| 705 | + settings.on_header_field = on_header_field; | ||
| 706 | + settings.on_header_value = on_header_value; | ||
| 707 | + settings.on_headers_complete = on_headers_complete; | ||
| 708 | + settings.on_body = on_body; | ||
| 709 | + settings.on_message_complete = on_message_complete; | ||
| 710 | + | ||
| 711 | + http_parser_init(&parser, type); | ||
| 712 | + // callback object ptr. | ||
| 713 | + parser.data = (void*)this; | ||
| 714 | + | ||
| 715 | + return ret; | ||
| 716 | +} | ||
| 717 | + | ||
| 718 | +int SrsHttpParser::parse_message(SrsStSocket* skt, SrsConnection* conn, ISrsHttpMessage** ppmsg) | ||
| 719 | +{ | ||
| 720 | + *ppmsg = NULL; | ||
| 721 | + | ||
| 722 | + int ret = ERROR_SUCCESS; | ||
| 723 | + | ||
| 724 | + // reset request data. | ||
| 725 | + field_name = ""; | ||
| 726 | + field_value = ""; | ||
| 727 | + expect_field_name = true; | ||
| 728 | + state = SrsHttpParseStateInit; | ||
| 729 | + header = http_parser(); | ||
| 730 | + url = ""; | ||
| 731 | + headers.clear(); | ||
| 732 | + header_parsed = 0; | ||
| 733 | + | ||
| 734 | + // do parse | ||
| 735 | + if ((ret = parse_message_imp(skt)) != ERROR_SUCCESS) { | ||
| 736 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 737 | + srs_error("parse http msg failed. ret=%d", ret); | ||
| 738 | + } | ||
| 739 | + return ret; | ||
| 740 | + } | ||
| 741 | + | ||
| 742 | + // create msg | ||
| 743 | + SrsHttpMessage* msg = new SrsHttpMessage(skt, conn); | ||
| 744 | + | ||
| 745 | + // initalize http msg, parse url. | ||
| 746 | + if ((ret = msg->update(url, &header, buffer, headers)) != ERROR_SUCCESS) { | ||
| 747 | + srs_error("initialize http msg failed. ret=%d", ret); | ||
| 748 | + srs_freep(msg); | ||
| 749 | + return ret; | ||
| 750 | + } | ||
| 751 | + | ||
| 752 | + // parse ok, return the msg. | ||
| 753 | + *ppmsg = msg; | ||
| 754 | + | ||
| 755 | + return ret; | ||
| 756 | +} | ||
| 757 | + | ||
| 758 | +int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | ||
| 759 | +{ | ||
| 760 | + int ret = ERROR_SUCCESS; | ||
| 761 | + | ||
| 762 | + while (true) { | ||
| 763 | + ssize_t nparsed = 0; | ||
| 764 | + | ||
| 765 | + // when got entire http header, parse it. | ||
| 766 | + // @see https://github.com/simple-rtmp-server/srs/issues/400 | ||
| 767 | + char* start = buffer->bytes(); | ||
| 768 | + char* end = start + buffer->size(); | ||
| 769 | + for (char* p = start; p <= end - 4; p++) { | ||
| 770 | + // SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A | ||
| 771 | + if (p[0] == SRS_CONSTS_CR && p[1] == SRS_CONSTS_LF && p[2] == SRS_CONSTS_CR && p[3] == SRS_CONSTS_LF) { | ||
| 772 | + nparsed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size()); | ||
| 773 | + srs_info("buffer=%d, nparsed=%d, header=%d", buffer->size(), (int)nparsed, header_parsed); | ||
| 774 | + break; | ||
| 775 | + } | ||
| 776 | + } | ||
| 777 | + | ||
| 778 | + // consume the parsed bytes. | ||
| 779 | + if (nparsed && header_parsed) { | ||
| 780 | + buffer->read_slice(header_parsed); | ||
| 781 | + } | ||
| 782 | + | ||
| 783 | + // ok atleast header completed, | ||
| 784 | + // never wait for body completed, for maybe chunked. | ||
| 785 | + if (state == SrsHttpParseStateHeaderComplete || state == SrsHttpParseStateMessageComplete) { | ||
| 786 | + break; | ||
| 787 | + } | ||
| 788 | + | ||
| 789 | + // when nothing parsed, read more to parse. | ||
| 790 | + if (nparsed == 0) { | ||
| 791 | + // when requires more, only grow 1bytes, but the buffer will cache more. | ||
| 792 | + if ((ret = buffer->grow(skt, buffer->size() + 1)) != ERROR_SUCCESS) { | ||
| 793 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 794 | + srs_error("read body from server failed. ret=%d", ret); | ||
| 795 | + } | ||
| 796 | + return ret; | ||
| 797 | + } | ||
| 798 | + } | ||
| 799 | + } | ||
| 800 | + | ||
| 801 | + // parse last header. | ||
| 802 | + if (!field_name.empty() && !field_value.empty()) { | ||
| 803 | + headers.push_back(std::make_pair(field_name, field_value)); | ||
| 804 | + } | ||
| 805 | + | ||
| 806 | + return ret; | ||
| 807 | +} | ||
| 808 | + | ||
| 809 | +int SrsHttpParser::on_message_begin(http_parser* parser) | ||
| 810 | +{ | ||
| 811 | + SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 812 | + srs_assert(obj); | ||
| 813 | + | ||
| 814 | + obj->state = SrsHttpParseStateStart; | ||
| 815 | + | ||
| 816 | + srs_info("***MESSAGE BEGIN***"); | ||
| 817 | + | ||
| 818 | + return 0; | ||
| 819 | +} | ||
| 820 | + | ||
| 821 | +int SrsHttpParser::on_headers_complete(http_parser* parser) | ||
| 822 | +{ | ||
| 823 | + SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 824 | + srs_assert(obj); | ||
| 825 | + | ||
| 826 | + obj->header = *parser; | ||
| 827 | + // save the parser when header parse completed. | ||
| 828 | + obj->state = SrsHttpParseStateHeaderComplete; | ||
| 829 | + obj->header_parsed = (int)parser->nread; | ||
| 830 | + | ||
| 831 | + srs_info("***HEADERS COMPLETE***"); | ||
| 832 | + | ||
| 833 | + // see http_parser.c:1570, return 1 to skip body. | ||
| 834 | + return 0; | ||
| 835 | +} | ||
| 836 | + | ||
| 837 | +int SrsHttpParser::on_message_complete(http_parser* parser) | ||
| 838 | +{ | ||
| 839 | + SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 840 | + srs_assert(obj); | ||
| 841 | + | ||
| 842 | + // save the parser when body parse completed. | ||
| 843 | + obj->state = SrsHttpParseStateMessageComplete; | ||
| 844 | + | ||
| 845 | + srs_info("***MESSAGE COMPLETE***\n"); | ||
| 846 | + | ||
| 847 | + return 0; | ||
| 848 | +} | ||
| 849 | + | ||
| 850 | +int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length) | ||
| 851 | +{ | ||
| 852 | + SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 853 | + srs_assert(obj); | ||
| 854 | + | ||
| 855 | + if (length > 0) { | ||
| 856 | + obj->url.append(at, (int)length); | ||
| 857 | + } | ||
| 858 | + | ||
| 859 | + srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at); | ||
| 860 | + | ||
| 861 | + return 0; | ||
| 862 | +} | ||
| 863 | + | ||
| 864 | +int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t length) | ||
| 865 | +{ | ||
| 866 | + SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 867 | + srs_assert(obj); | ||
| 868 | + | ||
| 869 | + // field value=>name, reap the field. | ||
| 870 | + if (!obj->expect_field_name) { | ||
| 871 | + obj->headers.push_back(std::make_pair(obj->field_name, obj->field_value)); | ||
| 872 | + | ||
| 873 | + // reset the field name when parsed. | ||
| 874 | + obj->field_name = ""; | ||
| 875 | + obj->field_value = ""; | ||
| 876 | + } | ||
| 877 | + obj->expect_field_name = true; | ||
| 878 | + | ||
| 879 | + if (length > 0) { | ||
| 880 | + obj->field_name.append(at, (int)length); | ||
| 881 | + } | ||
| 882 | + | ||
| 883 | + srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at); | ||
| 884 | + return 0; | ||
| 885 | +} | ||
| 886 | + | ||
| 887 | +int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t length) | ||
| 888 | +{ | ||
| 889 | + SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 890 | + srs_assert(obj); | ||
| 891 | + | ||
| 892 | + if (length > 0) { | ||
| 893 | + obj->field_value.append(at, (int)length); | ||
| 894 | + } | ||
| 895 | + obj->expect_field_name = false; | ||
| 896 | + | ||
| 897 | + srs_info("Header value(%d bytes): %.*s", (int)length, (int)length, at); | ||
| 898 | + return 0; | ||
| 899 | +} | ||
| 900 | + | ||
| 901 | +int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length) | ||
| 902 | +{ | ||
| 903 | + SrsHttpParser* obj = (SrsHttpParser*)parser->data; | ||
| 904 | + srs_assert(obj); | ||
| 905 | + | ||
| 906 | + srs_info("Body: %.*s", (int)length, at); | ||
| 907 | + | ||
| 908 | + return 0; | ||
| 909 | +} | ||
| 910 | + | ||
| 911 | +SrsHttpUri::SrsHttpUri() | ||
| 912 | +{ | ||
| 913 | + port = SRS_DEFAULT_HTTP_PORT; | ||
| 914 | +} | ||
| 915 | + | ||
| 916 | +SrsHttpUri::~SrsHttpUri() | ||
| 917 | +{ | ||
| 918 | +} | ||
| 919 | + | ||
| 920 | +int SrsHttpUri::initialize(string _url) | ||
| 921 | +{ | ||
| 922 | + int ret = ERROR_SUCCESS; | ||
| 923 | + | ||
| 924 | + url = _url; | ||
| 925 | + const char* purl = url.c_str(); | ||
| 926 | + | ||
| 927 | + http_parser_url hp_u; | ||
| 928 | + if((ret = http_parser_parse_url(purl, url.length(), 0, &hp_u)) != 0){ | ||
| 929 | + int code = ret; | ||
| 930 | + ret = ERROR_HTTP_PARSE_URI; | ||
| 931 | + | ||
| 932 | + srs_error("parse url %s failed, code=%d, ret=%d", purl, code, ret); | ||
| 933 | + return ret; | ||
| 934 | + } | ||
| 935 | + | ||
| 936 | + std::string field = get_uri_field(url, &hp_u, UF_SCHEMA); | ||
| 937 | + if(!field.empty()){ | ||
| 938 | + schema = field; | ||
| 939 | + } | ||
| 940 | + | ||
| 941 | + host = get_uri_field(url, &hp_u, UF_HOST); | ||
| 942 | + | ||
| 943 | + field = get_uri_field(url, &hp_u, UF_PORT); | ||
| 944 | + if(!field.empty()){ | ||
| 945 | + port = atoi(field.c_str()); | ||
| 946 | + } | ||
| 947 | + | ||
| 948 | + path = get_uri_field(url, &hp_u, UF_PATH); | ||
| 949 | + srs_info("parse url %s success", purl); | ||
| 950 | + | ||
| 951 | + query = get_uri_field(url, &hp_u, UF_QUERY); | ||
| 952 | + srs_info("parse query %s success", query.c_str()); | ||
| 953 | + | ||
| 954 | + return ret; | ||
| 955 | +} | ||
| 956 | + | ||
| 957 | +const char* SrsHttpUri::get_url() | ||
| 958 | +{ | ||
| 959 | + return url.data(); | ||
| 960 | +} | ||
| 961 | + | ||
| 962 | +const char* SrsHttpUri::get_schema() | ||
| 963 | +{ | ||
| 964 | + return schema.data(); | ||
| 965 | +} | ||
| 966 | + | ||
| 967 | +const char* SrsHttpUri::get_host() | ||
| 968 | +{ | ||
| 969 | + return host.data(); | ||
| 970 | +} | ||
| 971 | + | ||
| 972 | +int SrsHttpUri::get_port() | ||
| 973 | +{ | ||
| 974 | + return port; | ||
| 975 | +} | ||
| 976 | + | ||
| 977 | +const char* SrsHttpUri::get_path() | ||
| 978 | +{ | ||
| 979 | + return path.data(); | ||
| 980 | +} | ||
| 981 | + | ||
| 982 | +const char* SrsHttpUri::get_query() | ||
| 983 | +{ | ||
| 984 | + return query.data(); | ||
| 985 | +} | ||
| 986 | + | ||
| 987 | +string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field) | ||
| 988 | +{ | ||
| 989 | + if((hp_u->field_set & (1 << field)) == 0){ | ||
| 990 | + return ""; | ||
| 991 | + } | ||
| 992 | + | ||
| 993 | + srs_verbose("uri field matched, off=%d, len=%d, value=%.*s", | ||
| 994 | + hp_u->field_data[field].off, | ||
| 995 | + hp_u->field_data[field].len, | ||
| 996 | + hp_u->field_data[field].len, | ||
| 997 | + uri.c_str() + hp_u->field_data[field].off); | ||
| 998 | + | ||
| 999 | + int offset = hp_u->field_data[field].off; | ||
| 1000 | + int len = hp_u->field_data[field].len; | ||
| 1001 | + | ||
| 1002 | + return uri.substr(offset, len); | ||
| 1003 | +} | ||
| 1004 | + | ||
| 1005 | +#endif | ||
| 1006 | + | ||
| 1007 | +#ifdef SRS_AUTO_HTTP_SERVER | ||
| 1008 | + | ||
| 54 | SrsVodStream::SrsVodStream(string root_dir) | 1009 | SrsVodStream::SrsVodStream(string root_dir) |
| 55 | : SrsHttpFileServer(root_dir) | 1010 | : SrsHttpFileServer(root_dir) |
| 56 | { | 1011 | { |
| @@ -30,14 +30,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -30,14 +30,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 30 | 30 | ||
| 31 | #include <srs_core.hpp> | 31 | #include <srs_core.hpp> |
| 32 | 32 | ||
| 33 | -#ifdef SRS_AUTO_HTTP_SERVER | 33 | +#ifdef SRS_AUTO_HTTP_PARSER |
| 34 | +#include <http_parser.h> | ||
| 35 | +#endif | ||
| 36 | + | ||
| 37 | +#if defined(SRS_AUTO_HTTP_PARSER) || defined(SRS_AUTO_HTTP_SERVER) | ||
| 38 | + | ||
| 39 | +#include <map> | ||
| 40 | +#include <string> | ||
| 41 | +#include <vector> | ||
| 34 | 42 | ||
| 35 | #include <srs_app_st.hpp> | 43 | #include <srs_app_st.hpp> |
| 36 | -#include <srs_app_conn.hpp> | 44 | +#include <srs_http_stack.hpp> |
| 37 | #include <srs_app_http.hpp> | 45 | #include <srs_app_http.hpp> |
| 38 | #include <srs_app_reload.hpp> | 46 | #include <srs_app_reload.hpp> |
| 39 | #include <srs_kernel_file.hpp> | 47 | #include <srs_kernel_file.hpp> |
| 40 | #include <srs_app_thread.hpp> | 48 | #include <srs_app_thread.hpp> |
| 49 | +#include <srs_app_conn.hpp> | ||
| 41 | 50 | ||
| 42 | class SrsServer; | 51 | class SrsServer; |
| 43 | class SrsSource; | 52 | class SrsSource; |
| @@ -53,6 +62,309 @@ class ISrsHttpMessage; | @@ -53,6 +62,309 @@ class ISrsHttpMessage; | ||
| 53 | class SrsHttpHandler; | 62 | class SrsHttpHandler; |
| 54 | class SrsMessageQueue; | 63 | class SrsMessageQueue; |
| 55 | class SrsSharedPtrMessage; | 64 | class SrsSharedPtrMessage; |
| 65 | +class SrsRequest; | ||
| 66 | +class SrsFastBuffer; | ||
| 67 | +class SrsHttpUri; | ||
| 68 | +class SrsConnection; | ||
| 69 | +class SrsHttpMessage; | ||
| 70 | + | ||
| 71 | +#endif | ||
| 72 | + | ||
| 73 | +#ifdef SRS_AUTO_HTTP_PARSER | ||
| 74 | + | ||
| 75 | +/** | ||
| 76 | + * response writer use st socket | ||
| 77 | + */ | ||
| 78 | +class SrsHttpResponseWriter : public ISrsHttpResponseWriter | ||
| 79 | +{ | ||
| 80 | +private: | ||
| 81 | + SrsStSocket* skt; | ||
| 82 | + SrsHttpHeader* hdr; | ||
| 83 | +private: | ||
| 84 | + // reply header has been (logically) written | ||
| 85 | + bool header_wrote; | ||
| 86 | + // status code passed to WriteHeader | ||
| 87 | + int status; | ||
| 88 | +private: | ||
| 89 | + // explicitly-declared Content-Length; or -1 | ||
| 90 | + int64_t content_length; | ||
| 91 | + // number of bytes written in body | ||
| 92 | + int64_t written; | ||
| 93 | +private: | ||
| 94 | + // wroteHeader tells whether the header's been written to "the | ||
| 95 | + // wire" (or rather: w.conn.buf). this is unlike | ||
| 96 | + // (*response).wroteHeader, which tells only whether it was | ||
| 97 | + // logically written. | ||
| 98 | + bool header_sent; | ||
| 99 | +public: | ||
| 100 | + SrsHttpResponseWriter(SrsStSocket* io); | ||
| 101 | + virtual ~SrsHttpResponseWriter(); | ||
| 102 | +public: | ||
| 103 | + virtual int final_request(); | ||
| 104 | + virtual SrsHttpHeader* header(); | ||
| 105 | + virtual int write(char* data, int size); | ||
| 106 | + virtual void write_header(int code); | ||
| 107 | + virtual int send_header(char* data, int size); | ||
| 108 | +}; | ||
| 109 | + | ||
| 110 | +/** | ||
| 111 | + * response reader use st socket. | ||
| 112 | + */ | ||
| 113 | +class SrsHttpResponseReader : virtual public ISrsHttpResponseReader | ||
| 114 | +{ | ||
| 115 | +private: | ||
| 116 | + SrsStSocket* skt; | ||
| 117 | + SrsHttpMessage* owner; | ||
| 118 | + SrsFastBuffer* buffer; | ||
| 119 | + bool is_eof; | ||
| 120 | + // the left bytes in chunk. | ||
| 121 | + int nb_left_chunk; | ||
| 122 | + // the number of bytes of current chunk. | ||
| 123 | + int nb_chunk; | ||
| 124 | + // already read total bytes. | ||
| 125 | + int64_t nb_total_read; | ||
| 126 | +public: | ||
| 127 | + SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io); | ||
| 128 | + virtual ~SrsHttpResponseReader(); | ||
| 129 | +public: | ||
| 130 | + /** | ||
| 131 | + * initialize the response reader with buffer. | ||
| 132 | + */ | ||
| 133 | + virtual int initialize(SrsFastBuffer* buffer); | ||
| 134 | + // interface ISrsHttpResponseReader | ||
| 135 | +public: | ||
| 136 | + virtual bool eof(); | ||
| 137 | + virtual int read(char* data, int nb_data, int* nb_read); | ||
| 138 | +private: | ||
| 139 | + virtual int read_chunked(char* data, int nb_data, int* nb_read); | ||
| 140 | + virtual int read_specified(char* data, int nb_data, int* nb_read); | ||
| 141 | +}; | ||
| 142 | + | ||
| 143 | +// for http header. | ||
| 144 | +typedef std::pair<std::string, std::string> SrsHttpHeaderField; | ||
| 145 | + | ||
| 146 | +// A Request represents an HTTP request received by a server | ||
| 147 | +// or to be sent by a client. | ||
| 148 | +// | ||
| 149 | +// The field semantics differ slightly between client and server | ||
| 150 | +// usage. In addition to the notes on the fields below, see the | ||
| 151 | +// documentation for Request.Write and RoundTripper. | ||
| 152 | +/** | ||
| 153 | + * the http message, request or response. | ||
| 154 | + */ | ||
| 155 | +class SrsHttpMessage : public ISrsHttpMessage | ||
| 156 | +{ | ||
| 157 | +private: | ||
| 158 | + /** | ||
| 159 | + * parsed url. | ||
| 160 | + */ | ||
| 161 | + std::string _url; | ||
| 162 | + /** | ||
| 163 | + * the extension of file, for example, .flv | ||
| 164 | + */ | ||
| 165 | + std::string _ext; | ||
| 166 | + /** | ||
| 167 | + * parsed http header. | ||
| 168 | + */ | ||
| 169 | + http_parser _header; | ||
| 170 | + /** | ||
| 171 | + * body object, reader object. | ||
| 172 | + * @remark, user can get body in string by get_body(). | ||
| 173 | + */ | ||
| 174 | + SrsHttpResponseReader* _body; | ||
| 175 | + /** | ||
| 176 | + * whether the body is chunked. | ||
| 177 | + */ | ||
| 178 | + bool chunked; | ||
| 179 | + /** | ||
| 180 | + * whether the request indicates should keep alive | ||
| 181 | + * for the http connection. | ||
| 182 | + */ | ||
| 183 | + bool keep_alive; | ||
| 184 | + /** | ||
| 185 | + * uri parser | ||
| 186 | + */ | ||
| 187 | + SrsHttpUri* _uri; | ||
| 188 | + /** | ||
| 189 | + * use a buffer to read and send ts file. | ||
| 190 | + */ | ||
| 191 | + // TODO: FIXME: remove it. | ||
| 192 | + char* _http_ts_send_buffer; | ||
| 193 | + // http headers | ||
| 194 | + std::vector<SrsHttpHeaderField> _headers; | ||
| 195 | + // the query map | ||
| 196 | + std::map<std::string, std::string> _query; | ||
| 197 | + // the transport connection, can be NULL. | ||
| 198 | + SrsConnection* conn; | ||
| 199 | +public: | ||
| 200 | + SrsHttpMessage(SrsStSocket* io, SrsConnection* c); | ||
| 201 | + virtual ~SrsHttpMessage(); | ||
| 202 | +public: | ||
| 203 | + /** | ||
| 204 | + * set the original messages, then update the message. | ||
| 205 | + */ | ||
| 206 | + virtual int update(std::string url, http_parser* header, | ||
| 207 | + SrsFastBuffer* body, std::vector<SrsHttpHeaderField>& headers | ||
| 208 | + ); | ||
| 209 | +private: | ||
| 210 | + virtual SrsConnection* connection(); | ||
| 211 | +public: | ||
| 212 | + virtual u_int8_t method(); | ||
| 213 | + virtual u_int16_t status_code(); | ||
| 214 | + /** | ||
| 215 | + * method helpers. | ||
| 216 | + */ | ||
| 217 | + virtual std::string method_str(); | ||
| 218 | + virtual bool is_http_get(); | ||
| 219 | + virtual bool is_http_put(); | ||
| 220 | + virtual bool is_http_post(); | ||
| 221 | + virtual bool is_http_delete(); | ||
| 222 | + virtual bool is_http_options(); | ||
| 223 | + /** | ||
| 224 | + * whether body is chunked encoding, for reader only. | ||
| 225 | + */ | ||
| 226 | + virtual bool is_chunked(); | ||
| 227 | + /** | ||
| 228 | + * whether should keep the connection alive. | ||
| 229 | + */ | ||
| 230 | + virtual bool is_keep_alive(); | ||
| 231 | + /** | ||
| 232 | + * the uri contains the host and path. | ||
| 233 | + */ | ||
| 234 | + virtual std::string uri(); | ||
| 235 | + /** | ||
| 236 | + * the url maybe the path. | ||
| 237 | + */ | ||
| 238 | + virtual std::string url(); | ||
| 239 | + virtual std::string host(); | ||
| 240 | + virtual std::string path(); | ||
| 241 | + virtual std::string ext(); | ||
| 242 | +public: | ||
| 243 | + /** | ||
| 244 | + * read body to string. | ||
| 245 | + * @remark for small http body. | ||
| 246 | + */ | ||
| 247 | + virtual int body_read_all(std::string& body); | ||
| 248 | + /** | ||
| 249 | + * get the body reader, to read one by one. | ||
| 250 | + * @remark when body is very large, or chunked, use this. | ||
| 251 | + */ | ||
| 252 | + virtual ISrsHttpResponseReader* body_reader(); | ||
| 253 | + /** | ||
| 254 | + * the content length, -1 for chunked or not set. | ||
| 255 | + */ | ||
| 256 | + virtual int64_t content_length(); | ||
| 257 | + /** | ||
| 258 | + * get the param in query string, | ||
| 259 | + * for instance, query is "start=100&end=200", | ||
| 260 | + * then query_get("start") is "100", and query_get("end") is "200" | ||
| 261 | + */ | ||
| 262 | + virtual std::string query_get(std::string key); | ||
| 263 | + /** | ||
| 264 | + * get the headers. | ||
| 265 | + */ | ||
| 266 | + virtual int request_header_count(); | ||
| 267 | + virtual std::string request_header_key_at(int index); | ||
| 268 | + virtual std::string request_header_value_at(int index); | ||
| 269 | + virtual std::string get_request_header(std::string name); | ||
| 270 | +public: | ||
| 271 | + /** | ||
| 272 | + * convert the http message to a request. | ||
| 273 | + * @remark user must free the return request. | ||
| 274 | + */ | ||
| 275 | + virtual SrsRequest* to_request(std::string vhost); | ||
| 276 | +}; | ||
| 277 | + | ||
| 278 | +/** | ||
| 279 | + * wrapper for http-parser, | ||
| 280 | + * provides HTTP message originted service. | ||
| 281 | + */ | ||
| 282 | +class SrsHttpParser | ||
| 283 | +{ | ||
| 284 | +private: | ||
| 285 | + http_parser_settings settings; | ||
| 286 | + http_parser parser; | ||
| 287 | + // the global parse buffer. | ||
| 288 | + SrsFastBuffer* buffer; | ||
| 289 | +private: | ||
| 290 | + // http parse data, reset before parse message. | ||
| 291 | + bool expect_field_name; | ||
| 292 | + std::string field_name; | ||
| 293 | + std::string field_value; | ||
| 294 | + SrsHttpParseState state; | ||
| 295 | + http_parser header; | ||
| 296 | + std::string url; | ||
| 297 | + std::vector<SrsHttpHeaderField> headers; | ||
| 298 | + int header_parsed; | ||
| 299 | +public: | ||
| 300 | + SrsHttpParser(); | ||
| 301 | + virtual ~SrsHttpParser(); | ||
| 302 | +public: | ||
| 303 | + /** | ||
| 304 | + * initialize the http parser with specified type, | ||
| 305 | + * one parser can only parse request or response messages. | ||
| 306 | + */ | ||
| 307 | + virtual int initialize(enum http_parser_type type); | ||
| 308 | + /** | ||
| 309 | + * always parse a http message, | ||
| 310 | + * that is, the *ppmsg always NOT-NULL when return success. | ||
| 311 | + * or error and *ppmsg must be NULL. | ||
| 312 | + * @remark, if success, *ppmsg always NOT-NULL, *ppmsg always is_complete(). | ||
| 313 | + */ | ||
| 314 | + virtual int parse_message(SrsStSocket* skt, SrsConnection* conn, ISrsHttpMessage** ppmsg); | ||
| 315 | +private: | ||
| 316 | + /** | ||
| 317 | + * parse the HTTP message to member field: msg. | ||
| 318 | + */ | ||
| 319 | + virtual int parse_message_imp(SrsStSocket* skt); | ||
| 320 | +private: | ||
| 321 | + static int on_message_begin(http_parser* parser); | ||
| 322 | + static int on_headers_complete(http_parser* parser); | ||
| 323 | + static int on_message_complete(http_parser* parser); | ||
| 324 | + static int on_url(http_parser* parser, const char* at, size_t length); | ||
| 325 | + static int on_header_field(http_parser* parser, const char* at, size_t length); | ||
| 326 | + static int on_header_value(http_parser* parser, const char* at, size_t length); | ||
| 327 | + static int on_body(http_parser* parser, const char* at, size_t length); | ||
| 328 | +}; | ||
| 329 | + | ||
| 330 | +/** | ||
| 331 | + * used to resolve the http uri. | ||
| 332 | + */ | ||
| 333 | +class SrsHttpUri | ||
| 334 | +{ | ||
| 335 | +private: | ||
| 336 | + std::string url; | ||
| 337 | + std::string schema; | ||
| 338 | + std::string host; | ||
| 339 | + int port; | ||
| 340 | + std::string path; | ||
| 341 | + std::string query; | ||
| 342 | +public: | ||
| 343 | + SrsHttpUri(); | ||
| 344 | + virtual ~SrsHttpUri(); | ||
| 345 | +public: | ||
| 346 | + /** | ||
| 347 | + * initialize the http uri. | ||
| 348 | + */ | ||
| 349 | + virtual int initialize(std::string _url); | ||
| 350 | +public: | ||
| 351 | + virtual const char* get_url(); | ||
| 352 | + virtual const char* get_schema(); | ||
| 353 | + virtual const char* get_host(); | ||
| 354 | + virtual int get_port(); | ||
| 355 | + virtual const char* get_path(); | ||
| 356 | + virtual const char* get_query(); | ||
| 357 | +private: | ||
| 358 | + /** | ||
| 359 | + * get the parsed url field. | ||
| 360 | + * @return return empty string if not set. | ||
| 361 | + */ | ||
| 362 | + virtual std::string get_uri_field(std::string uri, http_parser_url* hp_u, http_parser_url_fields field); | ||
| 363 | +}; | ||
| 364 | + | ||
| 365 | +#endif | ||
| 366 | + | ||
| 367 | +#ifdef SRS_AUTO_HTTP_SERVER | ||
| 56 | 368 | ||
| 57 | /** | 369 | /** |
| 58 | * the flv vod stream supports flv?start=offset-bytes. | 370 | * the flv vod stream supports flv?start=offset-bytes. |
| @@ -38,6 +38,7 @@ using namespace std; | @@ -38,6 +38,7 @@ using namespace std; | ||
| 38 | #include <srs_core_autofree.hpp> | 38 | #include <srs_core_autofree.hpp> |
| 39 | #include <srs_app_config.hpp> | 39 | #include <srs_app_config.hpp> |
| 40 | #include <srs_kernel_utility.hpp> | 40 | #include <srs_kernel_utility.hpp> |
| 41 | +#include <srs_app_http_conn.hpp> | ||
| 41 | 42 | ||
| 42 | #define SRS_HTTP_RESPONSE_OK SRS_XSTR(ERROR_SUCCESS) | 43 | #define SRS_HTTP_RESPONSE_OK SRS_XSTR(ERROR_SUCCESS) |
| 43 | 44 |
| @@ -47,6 +47,7 @@ using namespace std; | @@ -47,6 +47,7 @@ using namespace std; | ||
| 47 | #include <srs_app_utility.hpp> | 47 | #include <srs_app_utility.hpp> |
| 48 | #include <srs_rtmp_amf0.hpp> | 48 | #include <srs_rtmp_amf0.hpp> |
| 49 | #include <srs_raw_avc.hpp> | 49 | #include <srs_raw_avc.hpp> |
| 50 | +#include <srs_app_http_conn.hpp> | ||
| 50 | 51 | ||
| 51 | // pre-declare | 52 | // pre-declare |
| 52 | int proxy_hls2rtmp(std::string hls, std::string rtmp); | 53 | int proxy_hls2rtmp(std::string hls, std::string rtmp); |
-
请 注册 或 登录 后发表评论