| 846 | } |
| 847 | |
| 848 | H2ParseResult H2Context::OnSettings( |
| 849 | butil::IOBufBytesIterator& it, const H2FrameHead& frame_head) { |
| 850 | // SETTINGS frames always apply to a connection, never a single stream. |
| 851 | // The stream identifier for a SETTINGS frame MUST be zero (0x0). If an |
| 852 | // endpoint receives a SETTINGS frame whose stream identifier field is |
| 853 | // anything other than 0x0, the endpoint MUST respond with a connection |
| 854 | // error (Section 5.4.1) of type PROTOCOL_ERROR. |
| 855 | if (frame_head.stream_id != 0) { |
| 856 | LOG(ERROR) << "Invalid stream_id=" << frame_head.stream_id; |
| 857 | return MakeH2Error(H2_PROTOCOL_ERROR); |
| 858 | } |
| 859 | if (frame_head.flags & H2_FLAGS_ACK) { |
| 860 | if (frame_head.payload_size != 0) { |
| 861 | LOG(ERROR) << "Non-zero payload_size=" << frame_head.payload_size |
| 862 | << " for settings-ACK"; |
| 863 | return MakeH2Error(H2_PROTOCOL_ERROR); |
| 864 | } |
| 865 | _local_settings = _unack_local_settings; |
| 866 | return MakeH2Message(NULL); |
| 867 | } |
| 868 | const int64_t old_stream_window_size = _remote_settings.stream_window_size; |
| 869 | if (!_remote_settings_received) { |
| 870 | // To solve the problem that sender can't send large request before receving |
| 871 | // remote setting, the initial window size of stream/connection is set to |
| 872 | // MAX_WINDOW_SIZE(see constructor of H2Context). |
| 873 | // As a result, in the view of remote side, window size is 65535 by default so |
| 874 | // it may not send its stream size to sender, making stream size still be |
| 875 | // MAX_WINDOW_SIZE. In this case we need to revert this value to default. |
| 876 | H2Settings tmp_settings; |
| 877 | if (!ParseH2Settings(&tmp_settings, it, frame_head.payload_size)) { |
| 878 | LOG(ERROR) << "Fail to parse from SETTINGS"; |
| 879 | return MakeH2Error(H2_PROTOCOL_ERROR); |
| 880 | } |
| 881 | _remote_settings = tmp_settings; |
| 882 | _remote_window_left.fetch_sub( |
| 883 | H2Settings::MAX_WINDOW_SIZE - H2Settings::DEFAULT_INITIAL_WINDOW_SIZE, |
| 884 | butil::memory_order_relaxed); |
| 885 | _remote_settings_received = true; |
| 886 | } else { |
| 887 | if (!ParseH2Settings(&_remote_settings, it, frame_head.payload_size)) { |
| 888 | LOG(ERROR) << "Fail to parse from SETTINGS"; |
| 889 | return MakeH2Error(H2_PROTOCOL_ERROR); |
| 890 | } |
| 891 | } |
| 892 | const int64_t window_diff = |
| 893 | static_cast<int64_t>(_remote_settings.stream_window_size) |
| 894 | - old_stream_window_size; |
| 895 | if (window_diff) { |
| 896 | // Do not update the connection flow-control window here, which can only |
| 897 | // be changed using WINDOW_UPDATE frames. |
| 898 | // https://tools.ietf.org/html/rfc7540#section-6.9.2 |
| 899 | // TODO(gejun): Has race conditions with AppendAndDestroySelf |
| 900 | std::unique_lock<butil::Mutex> mu(_stream_mutex); |
| 901 | for (StreamMap::const_iterator it = _pending_streams.begin(); |
| 902 | it != _pending_streams.end(); ++it) { |
| 903 | if (!AddWindowSize(&it->second->_remote_window_left, window_diff)) { |
| 904 | return MakeH2Error(H2_FLOW_CONTROL_ERROR); |
| 905 | } |
nothing calls this directly
no test coverage detected