| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/tools/balsa/balsa_frame.h" | 5 #include "net/tools/balsa/balsa_frame.h" |
| 6 | 6 |
| 7 #include <assert.h> | 7 #include <assert.h> |
| 8 #if __SSE2__ | 8 #if __SSE2__ |
| 9 #include <emmintrin.h> | 9 #include <emmintrin.h> |
| 10 #endif // __SSE2__ | 10 #endif // __SSE2__ |
| (...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 BalsaHeadersEnums::ContentLengthStatus* status, | 623 BalsaHeadersEnums::ContentLengthStatus* status, |
| 624 size_t* length) { | 624 size_t* length) { |
| 625 const HeaderLineDescription& header_line = headers_->header_lines_[line_idx]; | 625 const HeaderLineDescription& header_line = headers_->header_lines_[line_idx]; |
| 626 const char* stream_begin = headers_->OriginalHeaderStreamBegin(); | 626 const char* stream_begin = headers_->OriginalHeaderStreamBegin(); |
| 627 const char* line_end = stream_begin + header_line.last_char_idx; | 627 const char* line_end = stream_begin + header_line.last_char_idx; |
| 628 const char* value_begin = (stream_begin + header_line.value_begin_idx); | 628 const char* value_begin = (stream_begin + header_line.value_begin_idx); |
| 629 | 629 |
| 630 if (value_begin >= line_end) { | 630 if (value_begin >= line_end) { |
| 631 // There is no non-whitespace value data. | 631 // There is no non-whitespace value data. |
| 632 #if DEBUGFRAMER | 632 #if DEBUGFRAMER |
| 633 LOG(INFO) << "invalid content-length -- no non-whitespace value data"; | 633 VLOG(0) << "invalid content-length -- no non-whitespace value data"; |
| 634 #endif | 634 #endif |
| 635 *status = BalsaHeadersEnums::INVALID_CONTENT_LENGTH; | 635 *status = BalsaHeadersEnums::INVALID_CONTENT_LENGTH; |
| 636 return; | 636 return; |
| 637 } | 637 } |
| 638 | 638 |
| 639 *length = 0; | 639 *length = 0; |
| 640 while (value_begin < line_end) { | 640 while (value_begin < line_end) { |
| 641 if (*value_begin < '0' || *value_begin > '9') { | 641 if (*value_begin < '0' || *value_begin > '9') { |
| 642 // bad! content-length found, and couldn't parse all of it! | 642 // bad! content-length found, and couldn't parse all of it! |
| 643 *status = BalsaHeadersEnums::INVALID_CONTENT_LENGTH; | 643 *status = BalsaHeadersEnums::INVALID_CONTENT_LENGTH; |
| 644 #if DEBUGFRAMER | 644 #if DEBUGFRAMER |
| 645 LOG(INFO) << "invalid content-length - non numeric character detected"; | 645 VLOG(0) << "invalid content-length - non numeric character detected"; |
| 646 #endif // DEBUGFRAMER | 646 #endif // DEBUGFRAMER |
| 647 return; | 647 return; |
| 648 } | 648 } |
| 649 const size_t kMaxDiv10 = std::numeric_limits<size_t>::max() / 10; | 649 const size_t kMaxDiv10 = std::numeric_limits<size_t>::max() / 10; |
| 650 size_t length_x_10 = *length * 10; | 650 size_t length_x_10 = *length * 10; |
| 651 const unsigned char c = *value_begin - '0'; | 651 const unsigned char c = *value_begin - '0'; |
| 652 if (*length > kMaxDiv10 || | 652 if (*length > kMaxDiv10 || |
| 653 (std::numeric_limits<size_t>::max() - length_x_10) < c) { | 653 (std::numeric_limits<size_t>::max() - length_x_10) < c) { |
| 654 *status = BalsaHeadersEnums::CONTENT_LENGTH_OVERFLOW; | 654 *status = BalsaHeadersEnums::CONTENT_LENGTH_OVERFLOW; |
| 655 #if DEBUGFRAMER | 655 #if DEBUGFRAMER |
| 656 LOG(INFO) << "content-length overflow"; | 656 VLOG(0) << "content-length overflow"; |
| 657 #endif // DEBUGFRAMER | 657 #endif // DEBUGFRAMER |
| 658 return; | 658 return; |
| 659 } | 659 } |
| 660 *length = length_x_10 + c; | 660 *length = length_x_10 + c; |
| 661 ++value_begin; | 661 ++value_begin; |
| 662 } | 662 } |
| 663 #if DEBUGFRAMER | 663 #if DEBUGFRAMER |
| 664 LOG(INFO) << "content_length parsed: " << *length; | 664 VLOG(0) << "content_length parsed: " << *length; |
| 665 #endif // DEBUGFRAMER | 665 #endif // DEBUGFRAMER |
| 666 *status = BalsaHeadersEnums::VALID_CONTENT_LENGTH; | 666 *status = BalsaHeadersEnums::VALID_CONTENT_LENGTH; |
| 667 } | 667 } |
| 668 | 668 |
| 669 void BalsaFrame::ProcessTransferEncodingLine(HeaderLines::size_type line_idx) { | 669 void BalsaFrame::ProcessTransferEncodingLine(HeaderLines::size_type line_idx) { |
| 670 const HeaderLineDescription& header_line = headers_->header_lines_[line_idx]; | 670 const HeaderLineDescription& header_line = headers_->header_lines_[line_idx]; |
| 671 const char* stream_begin = headers_->OriginalHeaderStreamBegin(); | 671 const char* stream_begin = headers_->OriginalHeaderStreamBegin(); |
| 672 const char* line_end = stream_begin + header_line.last_char_idx; | 672 const char* line_end = stream_begin + header_line.last_char_idx; |
| 673 const char* value_begin = stream_begin + header_line.value_begin_idx; | 673 const char* value_begin = stream_begin + header_line.value_begin_idx; |
| 674 size_t value_length = line_end - value_begin; | 674 size_t value_length = line_end - value_begin; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 BalsaHeaders* extensions) { | 751 BalsaHeaders* extensions) { |
| 752 ProcessChunkExtensionsManual(base::StringPiece(input, size), extensions); | 752 ProcessChunkExtensionsManual(base::StringPiece(input, size), extensions); |
| 753 } | 753 } |
| 754 | 754 |
| 755 void BalsaFrame::ProcessHeaderLines() { | 755 void BalsaFrame::ProcessHeaderLines() { |
| 756 HeaderLines::size_type content_length_idx = 0; | 756 HeaderLines::size_type content_length_idx = 0; |
| 757 HeaderLines::size_type transfer_encoding_idx = 0; | 757 HeaderLines::size_type transfer_encoding_idx = 0; |
| 758 | 758 |
| 759 DCHECK(!lines_.empty()); | 759 DCHECK(!lines_.empty()); |
| 760 #if DEBUGFRAMER | 760 #if DEBUGFRAMER |
| 761 LOG(INFO) << "******@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**********\n"; | 761 VLOG(0) << "******@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**********\n"; |
| 762 #endif // DEBUGFRAMER | 762 #endif // DEBUGFRAMER |
| 763 | 763 |
| 764 // There is no need to attempt to process headers if no header lines exist. | 764 // There is no need to attempt to process headers if no header lines exist. |
| 765 // There are at least two lines in the message which are not header lines. | 765 // There are at least two lines in the message which are not header lines. |
| 766 // These two non-header lines are the first line of the message, and the | 766 // These two non-header lines are the first line of the message, and the |
| 767 // last line of the message (which is an empty line). | 767 // last line of the message (which is an empty line). |
| 768 // Thus, we test to see if we have more than two lines total before attempting | 768 // Thus, we test to see if we have more than two lines total before attempting |
| 769 // to parse any header lines. | 769 // to parse any header lines. |
| 770 if (lines_.size() > 2) { | 770 if (lines_.size() > 2) { |
| 771 const char* stream_begin = headers_->OriginalHeaderStreamBegin(); | 771 const char* stream_begin = headers_->OriginalHeaderStreamBegin(); |
| 772 | 772 |
| 773 // Then, for the rest of the header data, we parse these into key-value | 773 // Then, for the rest of the header data, we parse these into key-value |
| 774 // pairs. | 774 // pairs. |
| 775 FindColonsAndParseIntoKeyValue(); | 775 FindColonsAndParseIntoKeyValue(); |
| 776 // At this point, we've parsed all of the headers. Time to look for those | 776 // At this point, we've parsed all of the headers. Time to look for those |
| 777 // headers which we require for framing. | 777 // headers which we require for framing. |
| 778 const HeaderLines::size_type | 778 const HeaderLines::size_type |
| 779 header_lines_size = headers_->header_lines_.size(); | 779 header_lines_size = headers_->header_lines_.size(); |
| 780 for (HeaderLines::size_type i = 0; i < header_lines_size; ++i) { | 780 for (HeaderLines::size_type i = 0; i < header_lines_size; ++i) { |
| 781 const HeaderLineDescription& current_header_line = | 781 const HeaderLineDescription& current_header_line = |
| 782 headers_->header_lines_[i]; | 782 headers_->header_lines_[i]; |
| 783 const char* key_begin = | 783 const char* key_begin = |
| 784 (stream_begin + current_header_line.first_char_idx); | 784 (stream_begin + current_header_line.first_char_idx); |
| 785 const char* key_end = (stream_begin + current_header_line.key_end_idx); | 785 const char* key_end = (stream_begin + current_header_line.key_end_idx); |
| 786 const size_t key_len = key_end - key_begin; | 786 const size_t key_len = key_end - key_begin; |
| 787 const char c = *key_begin; | 787 const char c = *key_begin; |
| 788 #if DEBUGFRAMER | 788 #if DEBUGFRAMER |
| 789 LOG(INFO) << "[" << i << "]: " << std::string(key_begin, key_len) | 789 VLOG(0) << "[" << i << "]: " << std::string(key_begin, key_len) |
| 790 << " c: '" << c << "' key_len: " << key_len; | 790 << " c: '" << c << "' key_len: " << key_len; |
| 791 #endif // DEBUGFRAMER | 791 #endif // DEBUGFRAMER |
| 792 // If a header begins with either lowercase or uppercase 'c' or 't', then | 792 // If a header begins with either lowercase or uppercase 'c' or 't', then |
| 793 // the header may be one of content-length, connection, content-encoding | 793 // the header may be one of content-length, connection, content-encoding |
| 794 // or transfer-encoding. These headers are special, as they change the way | 794 // or transfer-encoding. These headers are special, as they change the way |
| 795 // that the message is framed, and so the framer is required to search | 795 // that the message is framed, and so the framer is required to search |
| 796 // for them. | 796 // for them. |
| 797 | 797 |
| 798 | 798 |
| 799 if (c == 'c' || c == 'C') { | 799 if (c == 'c' || c == 'C') { |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1004 const size_t relative_idx = message_current - message_start; | 1004 const size_t relative_idx = message_current - message_start; |
| 1005 const size_t message_current_idx = 1 + base_idx + relative_idx; | 1005 const size_t message_current_idx = 1 + base_idx + relative_idx; |
| 1006 lines_.push_back(std::make_pair(last_slash_n_idx_, | 1006 lines_.push_back(std::make_pair(last_slash_n_idx_, |
| 1007 message_current_idx)); | 1007 message_current_idx)); |
| 1008 if (lines_.size() == 1) { | 1008 if (lines_.size() == 1) { |
| 1009 headers_->WriteFromFramer(checkpoint, | 1009 headers_->WriteFromFramer(checkpoint, |
| 1010 1 + message_current - checkpoint); | 1010 1 + message_current - checkpoint); |
| 1011 checkpoint = message_current + 1; | 1011 checkpoint = message_current + 1; |
| 1012 const char* begin = headers_->OriginalHeaderStreamBegin(); | 1012 const char* begin = headers_->OriginalHeaderStreamBegin(); |
| 1013 #if DEBUGFRAMER | 1013 #if DEBUGFRAMER |
| 1014 LOG(INFO) << "First line " << std::string(begin, lines_[0].second); | 1014 VLOG(0) << "First line " << std::string(begin, lines_[0].second); |
| 1015 LOG(INFO) << "is_request_: " << is_request_; | 1015 VLOG(0) << "is_request_: " << is_request_; |
| 1016 #endif | 1016 #endif |
| 1017 ProcessFirstLine(begin, begin + lines_[0].second); | 1017 ProcessFirstLine(begin, begin + lines_[0].second); |
| 1018 if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ) | 1018 if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ) |
| 1019 goto process_lines; | 1019 goto process_lines; |
| 1020 else if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) | 1020 else if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) |
| 1021 goto bottom; | 1021 goto bottom; |
| 1022 } | 1022 } |
| 1023 const size_t chars_since_last_slash_n = (message_current_idx - | 1023 const size_t chars_since_last_slash_n = (message_current_idx - |
| 1024 last_slash_n_idx_); | 1024 last_slash_n_idx_); |
| 1025 last_slash_n_idx_ = message_current_idx; | 1025 last_slash_n_idx_ = message_current_idx; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1048 const size_t relative_idx = message_current - message_start; | 1048 const size_t relative_idx = message_current - message_start; |
| 1049 const size_t message_current_idx = 1 + base_idx + relative_idx; | 1049 const size_t message_current_idx = 1 + base_idx + relative_idx; |
| 1050 lines_.push_back(std::make_pair(last_slash_n_idx_, | 1050 lines_.push_back(std::make_pair(last_slash_n_idx_, |
| 1051 message_current_idx)); | 1051 message_current_idx)); |
| 1052 if (lines_.size() == 1) { | 1052 if (lines_.size() == 1) { |
| 1053 headers_->WriteFromFramer(checkpoint, | 1053 headers_->WriteFromFramer(checkpoint, |
| 1054 1 + message_current - checkpoint); | 1054 1 + message_current - checkpoint); |
| 1055 checkpoint = message_current + 1; | 1055 checkpoint = message_current + 1; |
| 1056 const char* begin = headers_->OriginalHeaderStreamBegin(); | 1056 const char* begin = headers_->OriginalHeaderStreamBegin(); |
| 1057 #if DEBUGFRAMER | 1057 #if DEBUGFRAMER |
| 1058 LOG(INFO) << "First line " << std::string(begin, lines_[0].second); | 1058 VLOG(0) << "First line " << std::string(begin, lines_[0].second); |
| 1059 LOG(INFO) << "is_request_: " << is_request_; | 1059 VLOG(0) << "is_request_: " << is_request_; |
| 1060 #endif | 1060 #endif |
| 1061 ProcessFirstLine(begin, begin + lines_[0].second); | 1061 ProcessFirstLine(begin, begin + lines_[0].second); |
| 1062 if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ) | 1062 if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ) |
| 1063 goto process_lines; | 1063 goto process_lines; |
| 1064 else if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) | 1064 else if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) |
| 1065 goto bottom; | 1065 goto bottom; |
| 1066 } | 1066 } |
| 1067 const size_t chars_since_last_slash_n = (message_current_idx - | 1067 const size_t chars_since_last_slash_n = (message_current_idx - |
| 1068 last_slash_n_idx_); | 1068 last_slash_n_idx_); |
| 1069 last_slash_n_idx_ = message_current_idx; | 1069 last_slash_n_idx_ = message_current_idx; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1212 // also one label at the bottom of the function. When it is appropriate to | 1212 // also one label at the bottom of the function. When it is appropriate to |
| 1213 // return from the function, that part of the state machine instead issues a | 1213 // return from the function, that part of the state machine instead issues a |
| 1214 // goto bottom; This results in less code duplication, and makes debugging | 1214 // goto bottom; This results in less code duplication, and makes debugging |
| 1215 // easier (as you can add a statement to a section of code which is guaranteed | 1215 // easier (as you can add a statement to a section of code which is guaranteed |
| 1216 // to be invoked when the function is exiting. | 1216 // to be invoked when the function is exiting. |
| 1217 size_t BalsaFrame::ProcessInput(const char* input, size_t size) { | 1217 size_t BalsaFrame::ProcessInput(const char* input, size_t size) { |
| 1218 const char* current = input; | 1218 const char* current = input; |
| 1219 const char* on_entry = current; | 1219 const char* on_entry = current; |
| 1220 const char* end = current + size; | 1220 const char* end = current + size; |
| 1221 #if DEBUGFRAMER | 1221 #if DEBUGFRAMER |
| 1222 LOG(INFO) << "\n==============" | 1222 VLOG(0) << "\n==============" |
| 1223 << BalsaFrameEnums::ParseStateToString(parse_state_) | 1223 << BalsaFrameEnums::ParseStateToString(parse_state_) |
| 1224 << "===============\n"; | 1224 << "===============\n"; |
| 1225 #endif // DEBUGFRAMER | 1225 #endif // DEBUGFRAMER |
| 1226 | 1226 |
| 1227 DCHECK(headers_ != NULL); | 1227 DCHECK(headers_ != NULL); |
| 1228 if (headers_ == NULL) return 0; | 1228 if (headers_ == NULL) return 0; |
| 1229 | 1229 |
| 1230 if (parse_state_ == BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE) { | 1230 if (parse_state_ == BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE) { |
| 1231 const size_t header_length = headers_->GetReadableBytesFromHeaderStream(); | 1231 const size_t header_length = headers_->GetReadableBytesFromHeaderStream(); |
| 1232 // Yes, we still have to check this here as the user can change the | 1232 // Yes, we still have to check this here as the user can change the |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1507 visitor_->ProcessBodyInput(current, bytes_remaining); | 1507 visitor_->ProcessBodyInput(current, bytes_remaining); |
| 1508 visitor_->ProcessBodyData(current, bytes_remaining); | 1508 visitor_->ProcessBodyData(current, bytes_remaining); |
| 1509 current += bytes_remaining; | 1509 current += bytes_remaining; |
| 1510 } | 1510 } |
| 1511 } | 1511 } |
| 1512 goto bottom; // case BalsaFrameEnums::READING_UNTIL_CLOSE | 1512 goto bottom; // case BalsaFrameEnums::READING_UNTIL_CLOSE |
| 1513 | 1513 |
| 1514 // label_reading_content: | 1514 // label_reading_content: |
| 1515 case BalsaFrameEnums::READING_CONTENT: | 1515 case BalsaFrameEnums::READING_CONTENT: |
| 1516 #if DEBUGFRAMER | 1516 #if DEBUGFRAMER |
| 1517 LOG(INFO) << "ReadingContent: " << content_length_remaining_; | 1517 VLOG(0) << "ReadingContent: " << content_length_remaining_; |
| 1518 #endif // DEBUGFRAMER | 1518 #endif // DEBUGFRAMER |
| 1519 while (content_length_remaining_ && current < end) { | 1519 while (content_length_remaining_ && current < end) { |
| 1520 // read in the content | 1520 // read in the content |
| 1521 const size_t bytes_remaining = end - current; | 1521 const size_t bytes_remaining = end - current; |
| 1522 const size_t consumed_bytes = | 1522 const size_t consumed_bytes = |
| 1523 (content_length_remaining_ < bytes_remaining) ? | 1523 (content_length_remaining_ < bytes_remaining) ? |
| 1524 content_length_remaining_ : bytes_remaining; | 1524 content_length_remaining_ : bytes_remaining; |
| 1525 visitor_->ProcessBodyInput(current, consumed_bytes); | 1525 visitor_->ProcessBodyInput(current, consumed_bytes); |
| 1526 visitor_->ProcessBodyData(current, consumed_bytes); | 1526 visitor_->ProcessBodyData(current, consumed_bytes); |
| 1527 current += consumed_bytes; | 1527 current += consumed_bytes; |
| 1528 content_length_remaining_ -= consumed_bytes; | 1528 content_length_remaining_ -= consumed_bytes; |
| 1529 } | 1529 } |
| 1530 if (content_length_remaining_ == 0) { | 1530 if (content_length_remaining_ == 0) { |
| 1531 parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; | 1531 parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; |
| 1532 visitor_->MessageDone(); | 1532 visitor_->MessageDone(); |
| 1533 } | 1533 } |
| 1534 goto bottom; // case BalsaFrameEnums::READING_CONTENT | 1534 goto bottom; // case BalsaFrameEnums::READING_CONTENT |
| 1535 | 1535 |
| 1536 default: | 1536 default: |
| 1537 // The state-machine should never be in a state that isn't handled | 1537 // The state-machine should never be in a state that isn't handled |
| 1538 // above. This is a glaring logic error, and we should do something | 1538 // above. This is a glaring logic error, and we should do something |
| 1539 // drastic to ensure that this gets looked-at and fixed. | 1539 // drastic to ensure that this gets looked-at and fixed. |
| 1540 LOG(FATAL) << "Unknown state: " << parse_state_ // COV_NF_LINE | 1540 LOG(FATAL) << "Unknown state: " << parse_state_ // COV_NF_LINE |
| 1541 << " memory corruption?!"; // COV_NF_LINE | 1541 << " memory corruption?!"; // COV_NF_LINE |
| 1542 } | 1542 } |
| 1543 } | 1543 } |
| 1544 bottom: | 1544 bottom: |
| 1545 #if DEBUGFRAMER | 1545 #if DEBUGFRAMER |
| 1546 LOG(INFO) << "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n" | 1546 VLOG(0) << "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n" |
| 1547 << std::string(input, current) | 1547 << std::string(input, current) |
| 1548 << "\n$$$$$$$$$$$$$$" | 1548 << "\n$$$$$$$$$$$$$$" |
| 1549 << BalsaFrameEnums::ParseStateToString(parse_state_) | 1549 << BalsaFrameEnums::ParseStateToString(parse_state_) |
| 1550 << "$$$$$$$$$$$$$$$" | 1550 << "$$$$$$$$$$$$$$$" |
| 1551 << " consumed: " << (current - input); | 1551 << " consumed: " << (current - input); |
| 1552 if (Error()) { | 1552 if (Error()) { |
| 1553 LOG(INFO) << BalsaFrameEnums::ErrorCodeToString(ErrorCode()); | 1553 VLOG(0) << BalsaFrameEnums::ErrorCodeToString(ErrorCode()); |
| 1554 } | 1554 } |
| 1555 #endif // DEBUGFRAMER | 1555 #endif // DEBUGFRAMER |
| 1556 return current - input; | 1556 return current - input; |
| 1557 } | 1557 } |
| 1558 | 1558 |
| 1559 const uint32 BalsaFrame::kValidTerm1; | 1559 const uint32 BalsaFrame::kValidTerm1; |
| 1560 const uint32 BalsaFrame::kValidTerm1Mask; | 1560 const uint32 BalsaFrame::kValidTerm1Mask; |
| 1561 const uint32 BalsaFrame::kValidTerm2; | 1561 const uint32 BalsaFrame::kValidTerm2; |
| 1562 const uint32 BalsaFrame::kValidTerm2Mask; | 1562 const uint32 BalsaFrame::kValidTerm2Mask; |
| 1563 | 1563 |
| 1564 } // namespace net | 1564 } // namespace net |
| OLD | NEW |