| 1247 | } |
| 1248 | |
| 1249 | bool |
| 1250 | HttpTransact::handle_upgrade_request(State *s) |
| 1251 | { |
| 1252 | HTTPHdr &request = s->hdr_info.client_request; |
| 1253 | s->method = request.method_get_wksidx(); |
| 1254 | |
| 1255 | // Quickest way to determine that this is defintely not an upgrade. |
| 1256 | /* RFC 6455 The method of the request MUST be GET, and the HTTP version MUST |
| 1257 | be at least 1.1. */ |
| 1258 | if (!s->hdr_info.client_request.presence(MIME_PRESENCE_UPGRADE) || |
| 1259 | !s->hdr_info.client_request.presence(MIME_PRESENCE_CONNECTION) || s->method != HTTP_WKSIDX_GET || |
| 1260 | s->hdr_info.client_request.version_get() < HTTP_1_1) { |
| 1261 | return false; |
| 1262 | } |
| 1263 | |
| 1264 | MIMEField *upgrade_hdr = s->hdr_info.client_request.field_find(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE); |
| 1265 | MIMEField *connection_hdr = s->hdr_info.client_request.field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION); |
| 1266 | |
| 1267 | StrList connection_hdr_vals; |
| 1268 | std::string_view upgrade_hdr_val; |
| 1269 | |
| 1270 | if (!upgrade_hdr || !connection_hdr || connection_hdr->value_get_comma_list(&connection_hdr_vals) == 0 || |
| 1271 | (upgrade_hdr_val = upgrade_hdr->value_get()).data() == nullptr) { |
| 1272 | TxnDbg(dbg_ctl_http_trans_upgrade, "Transaction wasn't a valid upgrade request, proceeding as a normal HTTP request."); |
| 1273 | return false; |
| 1274 | } |
| 1275 | |
| 1276 | /* |
| 1277 | * In order for this request to be treated as a normal upgrade request we must have a Connection: Upgrade header |
| 1278 | * and a Upgrade: header, with a non-empty value, otherwise we just assume it's not an Upgrade Request, after |
| 1279 | * we've verified that, we will try to match this upgrade to a known upgrade type such as Websockets. |
| 1280 | */ |
| 1281 | bool connection_contains_upgrade = false; |
| 1282 | // Next, let's validate that the Connection header contains an Upgrade key |
| 1283 | for (int i = 0; i < connection_hdr_vals.count; ++i) { |
| 1284 | Str *val = connection_hdr_vals.get_idx(i); |
| 1285 | if (ptr_len_casecmp(val->str, val->len, MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE) == 0) { |
| 1286 | connection_contains_upgrade = true; |
| 1287 | break; |
| 1288 | } |
| 1289 | } |
| 1290 | |
| 1291 | if (!connection_contains_upgrade) { |
| 1292 | TxnDbg(dbg_ctl_http_trans_upgrade, |
| 1293 | "Transaction wasn't a valid upgrade request, proceeding as a normal HTTP request, missing Connection upgrade header."); |
| 1294 | return false; |
| 1295 | } |
| 1296 | |
| 1297 | // Mark this request as an upgrade request. |
| 1298 | s->is_upgrade_request = true; |
| 1299 | |
| 1300 | /* |
| 1301 | RFC 6455 |
| 1302 | The request MUST contain an |Upgrade| header field whose value |
| 1303 | MUST include the "websocket" keyword. |
| 1304 | The request MUST contain a |Connection| header field whose value |
| 1305 | MUST include the "Upgrade" token. // Checked Above |
| 1306 | The request MUST include a header field with the name |
nothing calls this directly
no test coverage detected