正在显示
6 个修改的文件
包含
288 行增加
和
132 行删除
| @@ -74,6 +74,13 @@ function Ubuntu_prepare() | @@ -74,6 +74,13 @@ function Ubuntu_prepare() | ||
| 74 | echo "install patch success" | 74 | echo "install patch success" |
| 75 | fi | 75 | fi |
| 76 | 76 | ||
| 77 | + unzip --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then | ||
| 78 | + echo "install unzip" | ||
| 79 | + require_sudoer "sudo apt-get install -y --force-yes unzip" | ||
| 80 | + sudo apt-get install -y --force-yes unzip; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi | ||
| 81 | + echo "install unzip success" | ||
| 82 | + fi | ||
| 83 | + | ||
| 77 | if [ $SRS_FFMPEG_TOOL = YES ]; then | 84 | if [ $SRS_FFMPEG_TOOL = YES ]; then |
| 78 | autoconf --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then | 85 | autoconf --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then |
| 79 | echo "install autoconf" | 86 | echo "install autoconf" |
| @@ -170,6 +177,13 @@ function Centos_prepare() | @@ -170,6 +177,13 @@ function Centos_prepare() | ||
| 170 | echo "install patch success" | 177 | echo "install patch success" |
| 171 | fi | 178 | fi |
| 172 | 179 | ||
| 180 | + unzip --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then | ||
| 181 | + echo "install unzip" | ||
| 182 | + require_sudoer "sudo yum install -y unzip" | ||
| 183 | + sudo yum install -y unzip; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi | ||
| 184 | + echo "install unzip success" | ||
| 185 | + fi | ||
| 186 | + | ||
| 173 | if [ $SRS_FFMPEG_TOOL = YES ]; then | 187 | if [ $SRS_FFMPEG_TOOL = YES ]; then |
| 174 | automake --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then | 188 | automake --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then |
| 175 | echo "install automake" | 189 | echo "install automake" |
| @@ -43,6 +43,7 @@ using namespace std; | @@ -43,6 +43,7 @@ using namespace std; | ||
| 43 | #define SRS_DEFAULT_HTTP_PORT 80 | 43 | #define SRS_DEFAULT_HTTP_PORT 80 |
| 44 | 44 | ||
| 45 | #define SRS_HTTP_HEADER_BUFFER 1024 | 45 | #define SRS_HTTP_HEADER_BUFFER 1024 |
| 46 | +#define SRS_HTTP_BODY_BUFFER 1024 | ||
| 46 | 47 | ||
| 47 | // for http parser macros | 48 | // for http parser macros |
| 48 | #define SRS_CONSTS_HTTP_OPTIONS HTTP_OPTIONS | 49 | #define SRS_CONSTS_HTTP_OPTIONS HTTP_OPTIONS |
| @@ -227,6 +228,22 @@ ISrsHttpResponseWriter::~ISrsHttpResponseWriter() | @@ -227,6 +228,22 @@ ISrsHttpResponseWriter::~ISrsHttpResponseWriter() | ||
| 227 | { | 228 | { |
| 228 | } | 229 | } |
| 229 | 230 | ||
| 231 | +ISrsHttpResponseReader::ISrsHttpResponseReader() | ||
| 232 | +{ | ||
| 233 | +} | ||
| 234 | + | ||
| 235 | +ISrsHttpResponseReader::~ISrsHttpResponseReader() | ||
| 236 | +{ | ||
| 237 | +} | ||
| 238 | + | ||
| 239 | +ISrsHttpResponseAppender::ISrsHttpResponseAppender() | ||
| 240 | +{ | ||
| 241 | +} | ||
| 242 | + | ||
| 243 | +ISrsHttpResponseAppender::~ISrsHttpResponseAppender() | ||
| 244 | +{ | ||
| 245 | +} | ||
| 246 | + | ||
| 230 | ISrsHttpHandler::ISrsHttpHandler() | 247 | ISrsHttpHandler::ISrsHttpHandler() |
| 231 | { | 248 | { |
| 232 | entry = NULL; | 249 | entry = NULL; |
| @@ -833,11 +850,63 @@ int SrsHttpResponseWriter::send_header(char* data, int size) | @@ -833,11 +850,63 @@ int SrsHttpResponseWriter::send_header(char* data, int size) | ||
| 833 | return skt->write((void*)buf.c_str(), buf.length(), NULL); | 850 | return skt->write((void*)buf.c_str(), buf.length(), NULL); |
| 834 | } | 851 | } |
| 835 | 852 | ||
| 836 | -SrsHttpMessage::SrsHttpMessage() | 853 | +SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io) |
| 854 | +{ | ||
| 855 | + skt = io; | ||
| 856 | + owner = msg; | ||
| 857 | + cache = new SrsSimpleBuffer(); | ||
| 858 | +} | ||
| 859 | + | ||
| 860 | +SrsHttpResponseReader::~SrsHttpResponseReader() | ||
| 861 | +{ | ||
| 862 | + srs_freep(cache); | ||
| 863 | +} | ||
| 864 | + | ||
| 865 | +int SrsHttpResponseReader::read(int max, std::string& data) | ||
| 866 | +{ | ||
| 867 | + int ret = ERROR_SUCCESS; | ||
| 868 | + | ||
| 869 | + // read from cache first. | ||
| 870 | + if (cache->length() > 0) { | ||
| 871 | + int nb_bytes = srs_min(cache->length(), max); | ||
| 872 | + data.append(cache->bytes(), nb_bytes); | ||
| 873 | + cache->erase(nb_bytes); | ||
| 874 | + | ||
| 875 | + return ret; | ||
| 876 | + } | ||
| 877 | + | ||
| 878 | + // read some from underlayer. | ||
| 879 | + int left = srs_max(SRS_HTTP_BODY_BUFFER, max); | ||
| 880 | + | ||
| 881 | + // read from io. | ||
| 882 | + char* buf = new char[left]; | ||
| 883 | + SrsAutoFree(char, buf); | ||
| 884 | + | ||
| 885 | + ssize_t nread = 0; | ||
| 886 | + if ((ret = skt->read(buf, left, &nread)) != ERROR_SUCCESS) { | ||
| 887 | + return ret; | ||
| 888 | + } | ||
| 889 | + | ||
| 890 | + if (nread) { | ||
| 891 | + data.append(buf, nread); | ||
| 892 | + } | ||
| 893 | + | ||
| 894 | + return ret; | ||
| 895 | +} | ||
| 896 | + | ||
| 897 | +int SrsHttpResponseReader::append(char* data, int size) | ||
| 898 | +{ | ||
| 899 | + int ret = ERROR_SUCCESS; | ||
| 900 | + | ||
| 901 | + cache->append(data, size); | ||
| 902 | + | ||
| 903 | + return ret; | ||
| 904 | +} | ||
| 905 | + | ||
| 906 | +SrsHttpMessage::SrsHttpMessage(SrsStSocket* io) | ||
| 837 | { | 907 | { |
| 838 | - _body = new SrsSimpleBuffer(); | ||
| 839 | - _state = SrsHttpParseStateInit; | ||
| 840 | _uri = new SrsHttpUri(); | 908 | _uri = new SrsHttpUri(); |
| 909 | + _body = new SrsHttpResponseReader(this, io); | ||
| 841 | _http_ts_send_buffer = new char[__SRS_HTTP_TS_SEND_BUFFER_SIZE]; | 910 | _http_ts_send_buffer = new char[__SRS_HTTP_TS_SEND_BUFFER_SIZE]; |
| 842 | } | 911 | } |
| 843 | 912 | ||
| @@ -898,18 +967,6 @@ char* SrsHttpMessage::http_ts_send_buffer() | @@ -898,18 +967,6 @@ char* SrsHttpMessage::http_ts_send_buffer() | ||
| 898 | return _http_ts_send_buffer; | 967 | return _http_ts_send_buffer; |
| 899 | } | 968 | } |
| 900 | 969 | ||
| 901 | -void SrsHttpMessage::reset() | ||
| 902 | -{ | ||
| 903 | - _state = SrsHttpParseStateInit; | ||
| 904 | - _body->erase(_body->length()); | ||
| 905 | - _url = ""; | ||
| 906 | -} | ||
| 907 | - | ||
| 908 | -bool SrsHttpMessage::is_complete() | ||
| 909 | -{ | ||
| 910 | - return _state == SrsHttpParseStateComplete; | ||
| 911 | -} | ||
| 912 | - | ||
| 913 | u_int8_t SrsHttpMessage::method() | 970 | u_int8_t SrsHttpMessage::method() |
| 914 | { | 971 | { |
| 915 | return (u_int8_t)_header.method; | 972 | return (u_int8_t)_header.method; |
| @@ -993,25 +1050,49 @@ string SrsHttpMessage::path() | @@ -993,25 +1050,49 @@ string SrsHttpMessage::path() | ||
| 993 | return _uri->get_path(); | 1050 | return _uri->get_path(); |
| 994 | } | 1051 | } |
| 995 | 1052 | ||
| 996 | -string SrsHttpMessage::body() | 1053 | +void SrsHttpMessage::set(string url, http_parser* header, string body, vector<SrsHttpHeaderField>& headers) |
| 997 | { | 1054 | { |
| 998 | - std::string b; | ||
| 999 | - | ||
| 1000 | - if (_body && _body->length() > 0) { | ||
| 1001 | - b.append(_body->bytes(), _body->length()); | ||
| 1002 | - } | ||
| 1003 | - | ||
| 1004 | - return b; | ||
| 1005 | -} | 1055 | + _url = url; |
| 1056 | + _header = *header; | ||
| 1057 | + _headers = headers; | ||
| 1006 | 1058 | ||
| 1007 | -char* SrsHttpMessage::body_raw() | ||
| 1008 | -{ | ||
| 1009 | - return _body? _body->bytes() : NULL; | 1059 | + if (!body.empty()) { |
| 1060 | + _body->append((char*)body.data(), (int)body.length()); | ||
| 1061 | + } | ||
| 1010 | } | 1062 | } |
| 1011 | 1063 | ||
| 1012 | -int64_t SrsHttpMessage::body_size() | 1064 | +int SrsHttpMessage::body_read_all(string body) |
| 1013 | { | 1065 | { |
| 1014 | - return (int64_t)_body->length(); | 1066 | + int ret = ERROR_SUCCESS; |
| 1067 | + | ||
| 1068 | + // when content length specified, read specified length. | ||
| 1069 | + if ((int64_t)_header.content_length > 0) { | ||
| 1070 | + int left = (int)(int64_t)_header.content_length; | ||
| 1071 | + while (left > 0) { | ||
| 1072 | + int nb_read = (int)body.length(); | ||
| 1073 | + if ((ret = _body->read(left, body)) != ERROR_SUCCESS) { | ||
| 1074 | + return ret; | ||
| 1075 | + } | ||
| 1076 | + | ||
| 1077 | + left -= (int)body.length() - nb_read; | ||
| 1078 | + } | ||
| 1079 | + return ret; | ||
| 1080 | + } | ||
| 1081 | + | ||
| 1082 | + // chunked encoding, read util got size=0 chunk. | ||
| 1083 | + for (;;) { | ||
| 1084 | + int nb_read = (int)body.length(); | ||
| 1085 | + if ((ret = _body->read(0, body)) != ERROR_SUCCESS) { | ||
| 1086 | + return ret; | ||
| 1087 | + } | ||
| 1088 | + | ||
| 1089 | + // eof. | ||
| 1090 | + if (nb_read == (int)body.length()) { | ||
| 1091 | + break; | ||
| 1092 | + } | ||
| 1093 | + } | ||
| 1094 | + | ||
| 1095 | + return ret; | ||
| 1015 | } | 1096 | } |
| 1016 | 1097 | ||
| 1017 | int64_t SrsHttpMessage::content_length() | 1098 | int64_t SrsHttpMessage::content_length() |
| @@ -1019,26 +1100,6 @@ int64_t SrsHttpMessage::content_length() | @@ -1019,26 +1100,6 @@ int64_t SrsHttpMessage::content_length() | ||
| 1019 | return _header.content_length; | 1100 | return _header.content_length; |
| 1020 | } | 1101 | } |
| 1021 | 1102 | ||
| 1022 | -void SrsHttpMessage::set_url(string url) | ||
| 1023 | -{ | ||
| 1024 | - _url = url; | ||
| 1025 | -} | ||
| 1026 | - | ||
| 1027 | -void SrsHttpMessage::set_state(SrsHttpParseState state) | ||
| 1028 | -{ | ||
| 1029 | - _state = state; | ||
| 1030 | -} | ||
| 1031 | - | ||
| 1032 | -void SrsHttpMessage::set_header(http_parser* header) | ||
| 1033 | -{ | ||
| 1034 | - memcpy(&_header, header, sizeof(http_parser)); | ||
| 1035 | -} | ||
| 1036 | - | ||
| 1037 | -void SrsHttpMessage::append_body(const char* body, int length) | ||
| 1038 | -{ | ||
| 1039 | - _body->append(body, length); | ||
| 1040 | -} | ||
| 1041 | - | ||
| 1042 | string SrsHttpMessage::query_get(string key) | 1103 | string SrsHttpMessage::query_get(string key) |
| 1043 | { | 1104 | { |
| 1044 | std::string v; | 1105 | std::string v; |
| @@ -1052,33 +1113,28 @@ string SrsHttpMessage::query_get(string key) | @@ -1052,33 +1113,28 @@ string SrsHttpMessage::query_get(string key) | ||
| 1052 | 1113 | ||
| 1053 | int SrsHttpMessage::request_header_count() | 1114 | int SrsHttpMessage::request_header_count() |
| 1054 | { | 1115 | { |
| 1055 | - return (int)headers.size(); | 1116 | + return (int)_headers.size(); |
| 1056 | } | 1117 | } |
| 1057 | 1118 | ||
| 1058 | string SrsHttpMessage::request_header_key_at(int index) | 1119 | string SrsHttpMessage::request_header_key_at(int index) |
| 1059 | { | 1120 | { |
| 1060 | srs_assert(index < request_header_count()); | 1121 | srs_assert(index < request_header_count()); |
| 1061 | - SrsHttpHeaderField item = headers[index]; | 1122 | + SrsHttpHeaderField item = _headers[index]; |
| 1062 | return item.first; | 1123 | return item.first; |
| 1063 | } | 1124 | } |
| 1064 | 1125 | ||
| 1065 | string SrsHttpMessage::request_header_value_at(int index) | 1126 | string SrsHttpMessage::request_header_value_at(int index) |
| 1066 | { | 1127 | { |
| 1067 | srs_assert(index < request_header_count()); | 1128 | srs_assert(index < request_header_count()); |
| 1068 | - SrsHttpHeaderField item = headers[index]; | 1129 | + SrsHttpHeaderField item = _headers[index]; |
| 1069 | return item.second; | 1130 | return item.second; |
| 1070 | } | 1131 | } |
| 1071 | 1132 | ||
| 1072 | -void SrsHttpMessage::set_request_header(string key, string value) | ||
| 1073 | -{ | ||
| 1074 | - headers.push_back(std::make_pair(key, value)); | ||
| 1075 | -} | ||
| 1076 | - | ||
| 1077 | string SrsHttpMessage::get_request_header(string name) | 1133 | string SrsHttpMessage::get_request_header(string name) |
| 1078 | { | 1134 | { |
| 1079 | std::vector<SrsHttpHeaderField>::iterator it; | 1135 | std::vector<SrsHttpHeaderField>::iterator it; |
| 1080 | 1136 | ||
| 1081 | - for (it = headers.begin(); it != headers.end(); ++it) { | 1137 | + for (it = _headers.begin(); it != _headers.end(); ++it) { |
| 1082 | SrsHttpHeaderField& elem = *it; | 1138 | SrsHttpHeaderField& elem = *it; |
| 1083 | std::string key = elem.first; | 1139 | std::string key = elem.first; |
| 1084 | std::string value = elem.second; | 1140 | std::string value = elem.second; |
| @@ -1092,12 +1148,10 @@ string SrsHttpMessage::get_request_header(string name) | @@ -1092,12 +1148,10 @@ string SrsHttpMessage::get_request_header(string name) | ||
| 1092 | 1148 | ||
| 1093 | SrsHttpParser::SrsHttpParser() | 1149 | SrsHttpParser::SrsHttpParser() |
| 1094 | { | 1150 | { |
| 1095 | - msg = NULL; | ||
| 1096 | } | 1151 | } |
| 1097 | 1152 | ||
| 1098 | SrsHttpParser::~SrsHttpParser() | 1153 | SrsHttpParser::~SrsHttpParser() |
| 1099 | { | 1154 | { |
| 1100 | - srs_freep(msg); | ||
| 1101 | } | 1155 | } |
| 1102 | 1156 | ||
| 1103 | int SrsHttpParser::initialize(enum http_parser_type type) | 1157 | int SrsHttpParser::initialize(enum http_parser_type type) |
| @@ -1125,26 +1179,31 @@ int SrsHttpParser::parse_message(SrsStSocket* skt, SrsHttpMessage** ppmsg) | @@ -1125,26 +1179,31 @@ int SrsHttpParser::parse_message(SrsStSocket* skt, SrsHttpMessage** ppmsg) | ||
| 1125 | *ppmsg = NULL; | 1179 | *ppmsg = NULL; |
| 1126 | 1180 | ||
| 1127 | int ret = ERROR_SUCCESS; | 1181 | int ret = ERROR_SUCCESS; |
| 1128 | - | ||
| 1129 | - // the msg must be always NULL | ||
| 1130 | - srs_assert(msg == NULL); | ||
| 1131 | - msg = new SrsHttpMessage(); | ||
| 1132 | 1182 | ||
| 1133 | // reset request data. | 1183 | // reset request data. |
| 1134 | filed_name = ""; | 1184 | filed_name = ""; |
| 1135 | - | ||
| 1136 | - // reset response header. | ||
| 1137 | - msg->reset(); | 1185 | + field_value = ""; |
| 1186 | + expect_filed_name = true; | ||
| 1187 | + state = SrsHttpParseStateInit; | ||
| 1188 | + header = http_parser(); | ||
| 1189 | + url = ""; | ||
| 1190 | + headers.clear(); | ||
| 1191 | + body = ""; | ||
| 1138 | 1192 | ||
| 1139 | // do parse | 1193 | // do parse |
| 1140 | if ((ret = parse_message_imp(skt)) != ERROR_SUCCESS) { | 1194 | if ((ret = parse_message_imp(skt)) != ERROR_SUCCESS) { |
| 1141 | if (!srs_is_client_gracefully_close(ret)) { | 1195 | if (!srs_is_client_gracefully_close(ret)) { |
| 1142 | srs_error("parse http msg failed. ret=%d", ret); | 1196 | srs_error("parse http msg failed. ret=%d", ret); |
| 1143 | } | 1197 | } |
| 1144 | - srs_freep(msg); | ||
| 1145 | return ret; | 1198 | return ret; |
| 1146 | } | 1199 | } |
| 1147 | 1200 | ||
| 1201 | + // create msg | ||
| 1202 | + SrsHttpMessage* msg = new SrsHttpMessage(skt); | ||
| 1203 | + | ||
| 1204 | + // dumps the header and body read. | ||
| 1205 | + msg->set(url, &header, body, headers); | ||
| 1206 | + | ||
| 1148 | // initalize http msg, parse url. | 1207 | // initalize http msg, parse url. |
| 1149 | if ((ret = msg->initialize()) != ERROR_SUCCESS) { | 1208 | if ((ret = msg->initialize()) != ERROR_SUCCESS) { |
| 1150 | srs_error("initialize http msg failed. ret=%d", ret); | 1209 | srs_error("initialize http msg failed. ret=%d", ret); |
| @@ -1154,7 +1213,6 @@ int SrsHttpParser::parse_message(SrsStSocket* skt, SrsHttpMessage** ppmsg) | @@ -1154,7 +1213,6 @@ int SrsHttpParser::parse_message(SrsStSocket* skt, SrsHttpMessage** ppmsg) | ||
| 1154 | 1213 | ||
| 1155 | // parse ok, return the msg. | 1214 | // parse ok, return the msg. |
| 1156 | *ppmsg = msg; | 1215 | *ppmsg = msg; |
| 1157 | - msg = NULL; | ||
| 1158 | 1216 | ||
| 1159 | return ret; | 1217 | return ret; |
| 1160 | } | 1218 | } |
| @@ -1163,13 +1221,14 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | @@ -1163,13 +1221,14 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | ||
| 1163 | { | 1221 | { |
| 1164 | int ret = ERROR_SUCCESS; | 1222 | int ret = ERROR_SUCCESS; |
| 1165 | 1223 | ||
| 1166 | - // the msg should never be NULL | ||
| 1167 | - srs_assert(msg != NULL); | 1224 | + ssize_t nread = 0; |
| 1225 | + ssize_t nparsed = 0; | ||
| 1226 | + | ||
| 1227 | + char* buf = new char[SRS_HTTP_HEADER_BUFFER]; | ||
| 1228 | + SrsAutoFree(char, buf); | ||
| 1168 | 1229 | ||
| 1169 | // parser header. | 1230 | // parser header. |
| 1170 | - char buf[SRS_HTTP_HEADER_BUFFER]; | ||
| 1171 | for (;;) { | 1231 | for (;;) { |
| 1172 | - ssize_t nread; | ||
| 1173 | if ((ret = skt->read(buf, (size_t)sizeof(buf), &nread)) != ERROR_SUCCESS) { | 1232 | if ((ret = skt->read(buf, (size_t)sizeof(buf), &nread)) != ERROR_SUCCESS) { |
| 1174 | if (!srs_is_client_gracefully_close(ret)) { | 1233 | if (!srs_is_client_gracefully_close(ret)) { |
| 1175 | srs_error("read body from server failed. ret=%d", ret); | 1234 | srs_error("read body from server failed. ret=%d", ret); |
| @@ -1177,20 +1236,28 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | @@ -1177,20 +1236,28 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | ||
| 1177 | return ret; | 1236 | return ret; |
| 1178 | } | 1237 | } |
| 1179 | 1238 | ||
| 1180 | - ssize_t nparsed = http_parser_execute(&parser, &settings, buf, nread); | 1239 | + nparsed = http_parser_execute(&parser, &settings, buf, nread); |
| 1181 | srs_info("read_size=%d, nparsed=%d", (int)nread, (int)nparsed); | 1240 | srs_info("read_size=%d, nparsed=%d", (int)nread, (int)nparsed); |
| 1182 | 1241 | ||
| 1183 | - // check header size. | ||
| 1184 | - if (msg->is_complete()) { | ||
| 1185 | - return ret; | 1242 | + // ok atleast header completed, |
| 1243 | + // never wait for body completed, for maybe chunked. | ||
| 1244 | + if (state == SrsHttpParseStateHeaderComplete || state == SrsHttpParseStateMessageComplete) { | ||
| 1245 | + break; | ||
| 1186 | } | 1246 | } |
| 1187 | 1247 | ||
| 1248 | + // when not complete, the parser should consume all bytes. | ||
| 1188 | if (nparsed != nread) { | 1249 | if (nparsed != nread) { |
| 1189 | ret = ERROR_HTTP_PARSE_HEADER; | 1250 | ret = ERROR_HTTP_PARSE_HEADER; |
| 1190 | srs_error("parse response error, parsed(%d)!=read(%d), ret=%d", (int)nparsed, (int)nread, ret); | 1251 | srs_error("parse response error, parsed(%d)!=read(%d), ret=%d", (int)nparsed, (int)nread, ret); |
| 1191 | return ret; | 1252 | return ret; |
| 1192 | } | 1253 | } |
| 1193 | } | 1254 | } |
| 1255 | + | ||
| 1256 | + // when parse completed, cache the left body. | ||
| 1257 | + if (nread && nparsed < nread) { | ||
| 1258 | + body.append(buf + nparsed, nread - nparsed); | ||
| 1259 | + srs_info("cache %d bytes read body.", nread - nparsed); | ||
| 1260 | + } | ||
| 1194 | 1261 | ||
| 1195 | return ret; | 1262 | return ret; |
| 1196 | } | 1263 | } |
| @@ -1198,7 +1265,9 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | @@ -1198,7 +1265,9 @@ int SrsHttpParser::parse_message_imp(SrsStSocket* skt) | ||
| 1198 | int SrsHttpParser::on_message_begin(http_parser* parser) | 1265 | int SrsHttpParser::on_message_begin(http_parser* parser) |
| 1199 | { | 1266 | { |
| 1200 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; | 1267 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; |
| 1201 | - obj->msg->set_state(SrsHttpParseStateStart); | 1268 | + srs_assert(obj); |
| 1269 | + | ||
| 1270 | + obj->state = SrsHttpParseStateStart; | ||
| 1202 | 1271 | ||
| 1203 | srs_info("***MESSAGE BEGIN***"); | 1272 | srs_info("***MESSAGE BEGIN***"); |
| 1204 | 1273 | ||
| @@ -1208,7 +1277,11 @@ int SrsHttpParser::on_message_begin(http_parser* parser) | @@ -1208,7 +1277,11 @@ int SrsHttpParser::on_message_begin(http_parser* parser) | ||
| 1208 | int SrsHttpParser::on_headers_complete(http_parser* parser) | 1277 | int SrsHttpParser::on_headers_complete(http_parser* parser) |
| 1209 | { | 1278 | { |
| 1210 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; | 1279 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; |
| 1211 | - obj->msg->set_header(parser); | 1280 | + srs_assert(obj); |
| 1281 | + | ||
| 1282 | + obj->header = *parser; | ||
| 1283 | + // save the parser when header parse completed. | ||
| 1284 | + obj->state = SrsHttpParseStateHeaderComplete; | ||
| 1212 | 1285 | ||
| 1213 | srs_info("***HEADERS COMPLETE***"); | 1286 | srs_info("***HEADERS COMPLETE***"); |
| 1214 | 1287 | ||
| @@ -1219,8 +1292,10 @@ int SrsHttpParser::on_headers_complete(http_parser* parser) | @@ -1219,8 +1292,10 @@ int SrsHttpParser::on_headers_complete(http_parser* parser) | ||
| 1219 | int SrsHttpParser::on_message_complete(http_parser* parser) | 1292 | int SrsHttpParser::on_message_complete(http_parser* parser) |
| 1220 | { | 1293 | { |
| 1221 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; | 1294 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; |
| 1222 | - // save the parser when header parse completed. | ||
| 1223 | - obj->msg->set_state(SrsHttpParseStateComplete); | 1295 | + srs_assert(obj); |
| 1296 | + | ||
| 1297 | + // save the parser when body parse completed. | ||
| 1298 | + obj->state = SrsHttpParseStateMessageComplete; | ||
| 1224 | 1299 | ||
| 1225 | srs_info("***MESSAGE COMPLETE***\n"); | 1300 | srs_info("***MESSAGE COMPLETE***\n"); |
| 1226 | 1301 | ||
| @@ -1230,13 +1305,10 @@ int SrsHttpParser::on_message_complete(http_parser* parser) | @@ -1230,13 +1305,10 @@ int SrsHttpParser::on_message_complete(http_parser* parser) | ||
| 1230 | int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length) | 1305 | int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length) |
| 1231 | { | 1306 | { |
| 1232 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; | 1307 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; |
| 1308 | + srs_assert(obj); | ||
| 1233 | 1309 | ||
| 1234 | if (length > 0) { | 1310 | if (length > 0) { |
| 1235 | - std::string url; | ||
| 1236 | - | ||
| 1237 | - url.append(at, (int)length); | ||
| 1238 | - | ||
| 1239 | - obj->msg->set_url(url); | 1311 | + obj->url.append(at, (int)length); |
| 1240 | } | 1312 | } |
| 1241 | 1313 | ||
| 1242 | srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at); | 1314 | srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at); |
| @@ -1247,44 +1319,47 @@ int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length) | @@ -1247,44 +1319,47 @@ int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length) | ||
| 1247 | int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t length) | 1319 | int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t length) |
| 1248 | { | 1320 | { |
| 1249 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; | 1321 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; |
| 1322 | + srs_assert(obj); | ||
| 1323 | + | ||
| 1324 | + // field value=>name, reap the field. | ||
| 1325 | + if (!obj->expect_filed_name) { | ||
| 1326 | + obj->headers.push_back(std::make_pair(obj->filed_name, obj->field_value)); | ||
| 1327 | + | ||
| 1328 | + // reset the field name when value parsed. | ||
| 1329 | + obj->filed_name = ""; | ||
| 1330 | + obj->field_value = ""; | ||
| 1331 | + } | ||
| 1332 | + obj->expect_filed_name = true; | ||
| 1250 | 1333 | ||
| 1251 | if (length > 0) { | 1334 | if (length > 0) { |
| 1252 | - srs_assert(obj); | ||
| 1253 | obj->filed_name.append(at, (int)length); | 1335 | obj->filed_name.append(at, (int)length); |
| 1254 | } | 1336 | } |
| 1255 | 1337 | ||
| 1256 | - srs_info("Header field: %.*s", (int)length, at); | 1338 | + srs_trace("Header field: %.*s", (int)length, at); |
| 1257 | return 0; | 1339 | return 0; |
| 1258 | } | 1340 | } |
| 1259 | 1341 | ||
| 1260 | int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t length) | 1342 | int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t length) |
| 1261 | { | 1343 | { |
| 1262 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; | 1344 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; |
| 1345 | + srs_assert(obj); | ||
| 1263 | 1346 | ||
| 1264 | if (length > 0) { | 1347 | if (length > 0) { |
| 1265 | - srs_assert(obj); | ||
| 1266 | - srs_assert(obj->msg); | ||
| 1267 | - | ||
| 1268 | - std::string field_value; | ||
| 1269 | - field_value.append(at, (int)length); | ||
| 1270 | - | ||
| 1271 | - obj->msg->set_request_header(obj->filed_name, field_value); | ||
| 1272 | - obj->filed_name = ""; | 1348 | + obj->field_value.append(at, (int)length); |
| 1273 | } | 1349 | } |
| 1350 | + obj->expect_filed_name = false; | ||
| 1274 | 1351 | ||
| 1275 | - srs_info("Header value: %.*s", (int)length, at); | 1352 | + srs_trace("Header value: %.*s", (int)length, at); |
| 1276 | return 0; | 1353 | return 0; |
| 1277 | } | 1354 | } |
| 1278 | 1355 | ||
| 1279 | int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length) | 1356 | int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length) |
| 1280 | { | 1357 | { |
| 1281 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; | 1358 | SrsHttpParser* obj = (SrsHttpParser*)parser->data; |
| 1359 | + srs_assert(obj); | ||
| 1282 | 1360 | ||
| 1283 | if (length > 0) { | 1361 | if (length > 0) { |
| 1284 | - srs_assert(obj); | ||
| 1285 | - srs_assert(obj->msg); | ||
| 1286 | - | ||
| 1287 | - obj->msg->append_body(at, (int)length); | 1362 | + obj->body.append(at, (int)length); |
| 1288 | } | 1363 | } |
| 1289 | 1364 | ||
| 1290 | srs_info("Body: %.*s", (int)length, at); | 1365 | srs_info("Body: %.*s", (int)length, at); |
| @@ -76,7 +76,8 @@ extern int srs_go_http_response_json(ISrsHttpResponseWriter* w, std::string data | @@ -76,7 +76,8 @@ extern int srs_go_http_response_json(ISrsHttpResponseWriter* w, std::string data | ||
| 76 | enum SrsHttpParseState { | 76 | enum SrsHttpParseState { |
| 77 | SrsHttpParseStateInit = 0, | 77 | SrsHttpParseStateInit = 0, |
| 78 | SrsHttpParseStateStart, | 78 | SrsHttpParseStateStart, |
| 79 | - SrsHttpParseStateComplete | 79 | + SrsHttpParseStateHeaderComplete, |
| 80 | + SrsHttpParseStateMessageComplete | ||
| 80 | }; | 81 | }; |
| 81 | 82 | ||
| 82 | // A Header represents the key-value pairs in an HTTP header. | 83 | // A Header represents the key-value pairs in an HTTP header. |
| @@ -154,6 +155,8 @@ public: | @@ -154,6 +155,8 @@ public: | ||
| 154 | public: | 155 | public: |
| 155 | // when chunked mode, | 156 | // when chunked mode, |
| 156 | // final the request to complete the chunked encoding. | 157 | // final the request to complete the chunked encoding. |
| 158 | + // for no-chunked mode, | ||
| 159 | + // final to send request, for example, content-length is 0. | ||
| 157 | virtual int final_request() = 0; | 160 | virtual int final_request() = 0; |
| 158 | 161 | ||
| 159 | // Header returns the header map that will be sent by WriteHeader. | 162 | // Header returns the header map that will be sent by WriteHeader. |
| @@ -178,6 +181,39 @@ public: | @@ -178,6 +181,39 @@ public: | ||
| 178 | virtual void write_header(int code) = 0; | 181 | virtual void write_header(int code) = 0; |
| 179 | }; | 182 | }; |
| 180 | 183 | ||
| 184 | +/** | ||
| 185 | +* the reader interface for http response. | ||
| 186 | +*/ | ||
| 187 | +class ISrsHttpResponseReader | ||
| 188 | +{ | ||
| 189 | +public: | ||
| 190 | + ISrsHttpResponseReader(); | ||
| 191 | + virtual ~ISrsHttpResponseReader(); | ||
| 192 | +public: | ||
| 193 | + /** | ||
| 194 | + * read from the response body. | ||
| 195 | + * @param max the max size to read. 0 to ignore. | ||
| 196 | + */ | ||
| 197 | + virtual int read(int max, std::string& data) = 0; | ||
| 198 | +}; | ||
| 199 | + | ||
| 200 | +/** | ||
| 201 | +* for connection response only. | ||
| 202 | +*/ | ||
| 203 | +class ISrsHttpResponseAppender | ||
| 204 | +{ | ||
| 205 | +public: | ||
| 206 | + ISrsHttpResponseAppender(); | ||
| 207 | + virtual ~ISrsHttpResponseAppender(); | ||
| 208 | +public: | ||
| 209 | + /** | ||
| 210 | + * append specified size of bytes data to reader. | ||
| 211 | + * when we read http message from socket, we maybe read header+body, | ||
| 212 | + * so the reader should provides stream cache feature. | ||
| 213 | + */ | ||
| 214 | + virtual int append(char* data, int size) = 0; | ||
| 215 | +}; | ||
| 216 | + | ||
| 181 | // Objects implementing the Handler interface can be | 217 | // Objects implementing the Handler interface can be |
| 182 | // registered to serve a particular path or subtree | 218 | // registered to serve a particular path or subtree |
| 183 | // in the HTTP server. | 219 | // in the HTTP server. |
| @@ -366,6 +402,27 @@ public: | @@ -366,6 +402,27 @@ public: | ||
| 366 | virtual int send_header(char* data, int size); | 402 | virtual int send_header(char* data, int size); |
| 367 | }; | 403 | }; |
| 368 | 404 | ||
| 405 | +/** | ||
| 406 | +* response reader use st socket. | ||
| 407 | +*/ | ||
| 408 | +class SrsHttpResponseReader : virtual public ISrsHttpResponseReader | ||
| 409 | + , virtual public ISrsHttpResponseAppender | ||
| 410 | +{ | ||
| 411 | +private: | ||
| 412 | + SrsStSocket* skt; | ||
| 413 | + SrsHttpMessage* owner; | ||
| 414 | + SrsSimpleBuffer* cache; | ||
| 415 | +public: | ||
| 416 | + SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io); | ||
| 417 | + virtual ~SrsHttpResponseReader(); | ||
| 418 | +public: | ||
| 419 | + virtual int read(int max, std::string& data); | ||
| 420 | + virtual int append(char* data, int size); | ||
| 421 | +}; | ||
| 422 | + | ||
| 423 | +// for http header. | ||
| 424 | +typedef std::pair<std::string, std::string> SrsHttpHeaderField; | ||
| 425 | + | ||
| 369 | // A Request represents an HTTP request received by a server | 426 | // A Request represents an HTTP request received by a server |
| 370 | // or to be sent by a client. | 427 | // or to be sent by a client. |
| 371 | // | 428 | // |
| @@ -387,15 +444,10 @@ private: | @@ -387,15 +444,10 @@ private: | ||
| 387 | */ | 444 | */ |
| 388 | http_parser _header; | 445 | http_parser _header; |
| 389 | /** | 446 | /** |
| 390 | - * body object, in bytes. | 447 | + * body object, reader object. |
| 391 | * @remark, user can get body in string by get_body(). | 448 | * @remark, user can get body in string by get_body(). |
| 392 | */ | 449 | */ |
| 393 | - SrsSimpleBuffer* _body; | ||
| 394 | - /** | ||
| 395 | - * parser state | ||
| 396 | - * @remark, user can use is_complete() to determine the state. | ||
| 397 | - */ | ||
| 398 | - SrsHttpParseState _state; | 450 | + SrsHttpResponseReader* _body; |
| 399 | /** | 451 | /** |
| 400 | * uri parser | 452 | * uri parser |
| 401 | */ | 453 | */ |
| @@ -405,20 +457,17 @@ private: | @@ -405,20 +457,17 @@ private: | ||
| 405 | */ | 457 | */ |
| 406 | char* _http_ts_send_buffer; | 458 | char* _http_ts_send_buffer; |
| 407 | // http headers | 459 | // http headers |
| 408 | - typedef std::pair<std::string, std::string> SrsHttpHeaderField; | ||
| 409 | - std::vector<SrsHttpHeaderField> headers; | 460 | + std::vector<SrsHttpHeaderField> _headers; |
| 410 | // the query map | 461 | // the query map |
| 411 | std::map<std::string, std::string> _query; | 462 | std::map<std::string, std::string> _query; |
| 412 | public: | 463 | public: |
| 413 | - SrsHttpMessage(); | 464 | + SrsHttpMessage(SrsStSocket* io); |
| 414 | virtual ~SrsHttpMessage(); | 465 | virtual ~SrsHttpMessage(); |
| 415 | public: | 466 | public: |
| 416 | virtual int initialize(); | 467 | virtual int initialize(); |
| 417 | public: | 468 | public: |
| 418 | virtual char* http_ts_send_buffer(); | 469 | virtual char* http_ts_send_buffer(); |
| 419 | - virtual void reset(); | ||
| 420 | public: | 470 | public: |
| 421 | - virtual bool is_complete(); | ||
| 422 | virtual u_int8_t method(); | 471 | virtual u_int8_t method(); |
| 423 | virtual u_int16_t status_code(); | 472 | virtual u_int16_t status_code(); |
| 424 | virtual std::string method_str(); | 473 | virtual std::string method_str(); |
| @@ -432,14 +481,10 @@ public: | @@ -432,14 +481,10 @@ public: | ||
| 432 | virtual std::string host(); | 481 | virtual std::string host(); |
| 433 | virtual std::string path(); | 482 | virtual std::string path(); |
| 434 | public: | 483 | public: |
| 435 | - virtual std::string body(); | ||
| 436 | - virtual char* body_raw(); | ||
| 437 | - virtual int64_t body_size(); | 484 | + virtual void set(std::string url, http_parser* header, std::string body, std::vector<SrsHttpHeaderField>& headers); |
| 485 | +public: | ||
| 486 | + virtual int body_read_all(std::string body); | ||
| 438 | virtual int64_t content_length(); | 487 | virtual int64_t content_length(); |
| 439 | - virtual void set_url(std::string url); | ||
| 440 | - virtual void set_state(SrsHttpParseState state); | ||
| 441 | - virtual void set_header(http_parser* header); | ||
| 442 | - virtual void append_body(const char* body, int length); | ||
| 443 | /** | 488 | /** |
| 444 | * get the param in query string, | 489 | * get the param in query string, |
| 445 | * for instance, query is "start=100&end=200", | 490 | * for instance, query is "start=100&end=200", |
| @@ -449,7 +494,6 @@ public: | @@ -449,7 +494,6 @@ public: | ||
| 449 | virtual int request_header_count(); | 494 | virtual int request_header_count(); |
| 450 | virtual std::string request_header_key_at(int index); | 495 | virtual std::string request_header_key_at(int index); |
| 451 | virtual std::string request_header_value_at(int index); | 496 | virtual std::string request_header_value_at(int index); |
| 452 | - virtual void set_request_header(std::string key, std::string value); | ||
| 453 | virtual std::string get_request_header(std::string name); | 497 | virtual std::string get_request_header(std::string name); |
| 454 | }; | 498 | }; |
| 455 | 499 | ||
| @@ -462,8 +506,16 @@ class SrsHttpParser | @@ -462,8 +506,16 @@ class SrsHttpParser | ||
| 462 | private: | 506 | private: |
| 463 | http_parser_settings settings; | 507 | http_parser_settings settings; |
| 464 | http_parser parser; | 508 | http_parser parser; |
| 465 | - SrsHttpMessage* msg; | 509 | +private: |
| 510 | + // http parse data, reset before parse message. | ||
| 511 | + bool expect_filed_name; | ||
| 466 | std::string filed_name; | 512 | std::string filed_name; |
| 513 | + std::string field_value; | ||
| 514 | + SrsHttpParseState state; | ||
| 515 | + http_parser header; | ||
| 516 | + std::string url; | ||
| 517 | + std::vector<SrsHttpHeaderField> headers; | ||
| 518 | + std::string body; | ||
| 467 | public: | 519 | public: |
| 468 | SrsHttpParser(); | 520 | SrsHttpParser(); |
| 469 | virtual ~SrsHttpParser(); | 521 | virtual ~SrsHttpParser(); |
| @@ -527,13 +527,20 @@ int SrsHttpApi::do_cycle() | @@ -527,13 +527,20 @@ int SrsHttpApi::do_cycle() | ||
| 527 | return ret; | 527 | return ret; |
| 528 | } | 528 | } |
| 529 | 529 | ||
| 530 | - // if SUCCESS, always NOT-NULL and completed message. | 530 | + // if SUCCESS, always NOT-NULL. |
| 531 | srs_assert(req); | 531 | srs_assert(req); |
| 532 | - srs_assert(req->is_complete()); | ||
| 533 | 532 | ||
| 534 | // always free it in this scope. | 533 | // always free it in this scope. |
| 535 | SrsAutoFree(SrsHttpMessage, req); | 534 | SrsAutoFree(SrsHttpMessage, req); |
| 536 | 535 | ||
| 536 | + // TODO: FIXME: use the post body. | ||
| 537 | + std::string res; | ||
| 538 | + | ||
| 539 | + // get response body. | ||
| 540 | + if ((ret = req->body_read_all(res)) != ERROR_SUCCESS) { | ||
| 541 | + return ret; | ||
| 542 | + } | ||
| 543 | + | ||
| 537 | // ok, handle http request. | 544 | // ok, handle http request. |
| 538 | SrsHttpResponseWriter writer(&skt); | 545 | SrsHttpResponseWriter writer(&skt); |
| 539 | if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { | 546 | if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { |
| @@ -35,6 +35,7 @@ using namespace std; | @@ -35,6 +35,7 @@ using namespace std; | ||
| 35 | #include <srs_app_st_socket.hpp> | 35 | #include <srs_app_st_socket.hpp> |
| 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 | 39 | ||
| 39 | // when error, http client sleep for a while and retry. | 40 | // when error, http client sleep for a while and retry. |
| 40 | #define SRS_HTTP_CLIENT_SLEEP_US (int64_t)(3*1000*1000LL) | 41 | #define SRS_HTTP_CLIENT_SLEEP_US (int64_t)(3*1000*1000LL) |
| @@ -103,18 +104,18 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r | @@ -103,18 +104,18 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r | ||
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | srs_assert(msg); | 106 | srs_assert(msg); |
| 106 | - srs_assert(msg->is_complete()); | 107 | + |
| 108 | + // always free it in this scope. | ||
| 109 | + SrsAutoFree(SrsHttpMessage, msg); | ||
| 107 | 110 | ||
| 108 | status_code = (int)msg->status_code(); | 111 | status_code = (int)msg->status_code(); |
| 109 | 112 | ||
| 110 | // get response body. | 113 | // get response body. |
| 111 | - if (msg->body_size() > 0) { | ||
| 112 | - res = msg->body(); | 114 | + if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) { |
| 115 | + return ret; | ||
| 113 | } | 116 | } |
| 114 | srs_info("parse http post response success."); | 117 | srs_info("parse http post response success."); |
| 115 | 118 | ||
| 116 | - srs_freep(msg); | ||
| 117 | - | ||
| 118 | return ret; | 119 | return ret; |
| 119 | } | 120 | } |
| 120 | 121 |
| @@ -1194,13 +1194,20 @@ int SrsHttpConn::do_cycle() | @@ -1194,13 +1194,20 @@ int SrsHttpConn::do_cycle() | ||
| 1194 | return ret; | 1194 | return ret; |
| 1195 | } | 1195 | } |
| 1196 | 1196 | ||
| 1197 | - // if SUCCESS, always NOT-NULL and completed message. | 1197 | + // if SUCCESS, always NOT-NULL. |
| 1198 | srs_assert(req); | 1198 | srs_assert(req); |
| 1199 | - srs_assert(req->is_complete()); | ||
| 1200 | 1199 | ||
| 1201 | // always free it in this scope. | 1200 | // always free it in this scope. |
| 1202 | SrsAutoFree(SrsHttpMessage, req); | 1201 | SrsAutoFree(SrsHttpMessage, req); |
| 1203 | 1202 | ||
| 1203 | + // TODO: FIXME: use the post body. | ||
| 1204 | + std::string res; | ||
| 1205 | + | ||
| 1206 | + // get response body. | ||
| 1207 | + if ((ret = req->body_read_all(res)) != ERROR_SUCCESS) { | ||
| 1208 | + return ret; | ||
| 1209 | + } | ||
| 1210 | + | ||
| 1204 | // ok, handle http request. | 1211 | // ok, handle http request. |
| 1205 | SrsHttpResponseWriter writer(&skt); | 1212 | SrsHttpResponseWriter writer(&skt); |
| 1206 | if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { | 1213 | if ((ret = process_request(&writer, req)) != ERROR_SUCCESS) { |
-
请 注册 或 登录 后发表评论