| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/ftp/ftp_network_transaction.h" | 5 #include "net/ftp/ftp_network_transaction.h" |
| 6 | 6 |
| 7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 resource_type_(RESOURCE_TYPE_UNKNOWN), | 197 resource_type_(RESOURCE_TYPE_UNKNOWN), |
| 198 use_epsv_(true), | 198 use_epsv_(true), |
| 199 data_connection_port_(0), | 199 data_connection_port_(0), |
| 200 socket_factory_(socket_factory), | 200 socket_factory_(socket_factory), |
| 201 next_state_(STATE_NONE) { | 201 next_state_(STATE_NONE) { |
| 202 } | 202 } |
| 203 | 203 |
| 204 FtpNetworkTransaction::~FtpNetworkTransaction() { | 204 FtpNetworkTransaction::~FtpNetworkTransaction() { |
| 205 } | 205 } |
| 206 | 206 |
| 207 int FtpNetworkTransaction::Stop(int error) { |
| 208 if (command_sent_ == COMMAND_QUIT) |
| 209 return error; |
| 210 |
| 211 next_state_ = STATE_CTRL_WRITE_QUIT; |
| 212 last_error_ = error; |
| 213 return OK; |
| 214 } |
| 215 |
| 216 int FtpNetworkTransaction::RestartIgnoringLastError( |
| 217 CompletionCallback* callback) { |
| 218 return ERR_NOT_IMPLEMENTED; |
| 219 } |
| 220 |
| 207 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, | 221 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, |
| 208 CompletionCallback* callback, | 222 CompletionCallback* callback, |
| 209 const BoundNetLog& net_log) { | 223 const BoundNetLog& net_log) { |
| 210 net_log_ = net_log; | 224 net_log_ = net_log; |
| 211 request_ = request_info; | 225 request_ = request_info; |
| 212 | 226 |
| 213 if (request_->url.has_username()) { | 227 if (request_->url.has_username()) { |
| 214 GetIdentityFromURL(request_->url, &username_, &password_); | 228 GetIdentityFromURL(request_->url, &username_, &password_); |
| 215 } else { | 229 } else { |
| 216 username_ = ASCIIToUTF16("anonymous"); | 230 username_ = ASCIIToUTF16("anonymous"); |
| 217 password_ = ASCIIToUTF16("chrome@example.com"); | 231 password_ = ASCIIToUTF16("chrome@example.com"); |
| 218 } | 232 } |
| 219 | 233 |
| 220 DetectTypecode(); | 234 DetectTypecode(); |
| 221 | 235 |
| 222 next_state_ = STATE_CTRL_RESOLVE_HOST; | 236 next_state_ = STATE_CTRL_RESOLVE_HOST; |
| 223 int rv = DoLoop(OK); | 237 int rv = DoLoop(OK); |
| 224 if (rv == ERR_IO_PENDING) | 238 if (rv == ERR_IO_PENDING) |
| 225 user_callback_ = callback; | 239 user_callback_ = callback; |
| 226 return rv; | 240 return rv; |
| 227 } | 241 } |
| 228 | 242 |
| 229 int FtpNetworkTransaction::Stop(int error) { | |
| 230 if (command_sent_ == COMMAND_QUIT) | |
| 231 return error; | |
| 232 | |
| 233 next_state_ = STATE_CTRL_WRITE_QUIT; | |
| 234 last_error_ = error; | |
| 235 return OK; | |
| 236 } | |
| 237 | |
| 238 int FtpNetworkTransaction::RestartWithAuth(const string16& username, | 243 int FtpNetworkTransaction::RestartWithAuth(const string16& username, |
| 239 const string16& password, | 244 const string16& password, |
| 240 CompletionCallback* callback) { | 245 CompletionCallback* callback) { |
| 241 ResetStateForRestart(); | 246 ResetStateForRestart(); |
| 242 | 247 |
| 243 username_ = username; | 248 username_ = username; |
| 244 password_ = password; | 249 password_ = password; |
| 245 | 250 |
| 246 next_state_ = STATE_CTRL_RESOLVE_HOST; | 251 next_state_ = STATE_CTRL_RESOLVE_HOST; |
| 247 int rv = DoLoop(OK); | 252 int rv = DoLoop(OK); |
| 248 if (rv == ERR_IO_PENDING) | 253 if (rv == ERR_IO_PENDING) |
| 249 user_callback_ = callback; | 254 user_callback_ = callback; |
| 250 return rv; | 255 return rv; |
| 251 } | 256 } |
| 252 | 257 |
| 253 int FtpNetworkTransaction::RestartIgnoringLastError( | |
| 254 CompletionCallback* callback) { | |
| 255 return ERR_NOT_IMPLEMENTED; | |
| 256 } | |
| 257 | |
| 258 int FtpNetworkTransaction::Read(IOBuffer* buf, | 258 int FtpNetworkTransaction::Read(IOBuffer* buf, |
| 259 int buf_len, | 259 int buf_len, |
| 260 CompletionCallback* callback) { | 260 CompletionCallback* callback) { |
| 261 DCHECK(buf); | 261 DCHECK(buf); |
| 262 DCHECK_GT(buf_len, 0); | 262 DCHECK_GT(buf_len, 0); |
| 263 | 263 |
| 264 read_data_buf_ = buf; | 264 read_data_buf_ = buf; |
| 265 read_data_buf_len_ = buf_len; | 265 read_data_buf_len_ = buf_len; |
| 266 | 266 |
| 267 next_state_ = STATE_DATA_READ; | 267 next_state_ = STATE_DATA_READ; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 295 if (command_sent_ != COMMAND_NONE) | 295 if (command_sent_ != COMMAND_NONE) |
| 296 return LOAD_STATE_SENDING_REQUEST; | 296 return LOAD_STATE_SENDING_REQUEST; |
| 297 | 297 |
| 298 return LOAD_STATE_IDLE; | 298 return LOAD_STATE_IDLE; |
| 299 } | 299 } |
| 300 | 300 |
| 301 uint64 FtpNetworkTransaction::GetUploadProgress() const { | 301 uint64 FtpNetworkTransaction::GetUploadProgress() const { |
| 302 return 0; | 302 return 0; |
| 303 } | 303 } |
| 304 | 304 |
| 305 // Used to prepare and send FTP command. | 305 void FtpNetworkTransaction::ResetStateForRestart() { |
| 306 int FtpNetworkTransaction::SendFtpCommand(const std::string& command, | 306 command_sent_ = COMMAND_NONE; |
| 307 Command cmd) { | 307 user_callback_ = NULL; |
| 308 // If we send a new command when we still have unprocessed responses | 308 response_ = FtpResponseInfo(); |
| 309 // for previous commands, the response receiving code will have no way to know | 309 read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); |
| 310 // which responses are for which command. | 310 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer()); |
| 311 DCHECK(!ctrl_response_buffer_->ResponseAvailable()); | 311 read_data_buf_ = NULL; |
| 312 read_data_buf_len_ = 0; |
| 313 if (write_buf_) |
| 314 write_buf_->SetOffset(0); |
| 315 last_error_ = OK; |
| 316 data_connection_port_ = 0; |
| 317 ctrl_socket_.reset(); |
| 318 data_socket_.reset(); |
| 319 next_state_ = STATE_NONE; |
| 320 } |
| 312 | 321 |
| 313 DCHECK(!write_command_buf_); | 322 void FtpNetworkTransaction::DoCallback(int rv) { |
| 314 DCHECK(!write_buf_); | 323 DCHECK(rv != ERR_IO_PENDING); |
| 324 DCHECK(user_callback_); |
| 315 | 325 |
| 316 if (!IsValidFTPCommandString(command)) { | 326 // Since Run may result in Read being called, clear callback_ up front. |
| 317 // Callers should validate the command themselves and return a more specific | 327 CompletionCallback* c = user_callback_; |
| 318 // error code. | 328 user_callback_ = NULL; |
| 319 NOTREACHED(); | 329 c->Run(rv); |
| 320 return Stop(ERR_UNEXPECTED); | 330 } |
| 321 } | |
| 322 | 331 |
| 323 command_sent_ = cmd; | 332 void FtpNetworkTransaction::OnIOComplete(int result) { |
| 324 | 333 int rv = DoLoop(result); |
| 325 write_command_buf_ = new IOBufferWithSize(command.length() + 2); | 334 if (rv != ERR_IO_PENDING) |
| 326 write_buf_ = new DrainableIOBuffer(write_command_buf_, | 335 DoCallback(rv); |
| 327 write_command_buf_->size()); | |
| 328 memcpy(write_command_buf_->data(), command.data(), command.length()); | |
| 329 memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); | |
| 330 | |
| 331 next_state_ = STATE_CTRL_WRITE; | |
| 332 return OK; | |
| 333 } | 336 } |
| 334 | 337 |
| 335 int FtpNetworkTransaction::ProcessCtrlResponse() { | 338 int FtpNetworkTransaction::ProcessCtrlResponse() { |
| 336 FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); | 339 FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); |
| 337 | 340 |
| 338 int rv = OK; | 341 int rv = OK; |
| 339 switch (command_sent_) { | 342 switch (command_sent_) { |
| 340 case COMMAND_NONE: | 343 case COMMAND_NONE: |
| 341 // TODO(phajdan.jr): Check for errors in the welcome message. | 344 // TODO(phajdan.jr): Check for errors in the welcome message. |
| 342 next_state_ = STATE_CTRL_WRITE_USER; | 345 next_state_ = STATE_CTRL_WRITE_USER; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 break; | 399 break; |
| 397 default: | 400 default: |
| 398 // Multiple responses for other commands are invalid. | 401 // Multiple responses for other commands are invalid. |
| 399 return Stop(ERR_INVALID_RESPONSE); | 402 return Stop(ERR_INVALID_RESPONSE); |
| 400 } | 403 } |
| 401 } | 404 } |
| 402 | 405 |
| 403 return rv; | 406 return rv; |
| 404 } | 407 } |
| 405 | 408 |
| 406 void FtpNetworkTransaction::ResetStateForRestart() { | 409 // Used to prepare and send FTP command. |
| 407 command_sent_ = COMMAND_NONE; | 410 int FtpNetworkTransaction::SendFtpCommand(const std::string& command, |
| 408 user_callback_ = NULL; | 411 Command cmd) { |
| 409 response_ = FtpResponseInfo(); | 412 // If we send a new command when we still have unprocessed responses |
| 410 read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); | 413 // for previous commands, the response receiving code will have no way to know |
| 411 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer()); | 414 // which responses are for which command. |
| 412 read_data_buf_ = NULL; | 415 DCHECK(!ctrl_response_buffer_->ResponseAvailable()); |
| 413 read_data_buf_len_ = 0; | |
| 414 if (write_buf_) | |
| 415 write_buf_->SetOffset(0); | |
| 416 last_error_ = OK; | |
| 417 data_connection_port_ = 0; | |
| 418 ctrl_socket_.reset(); | |
| 419 data_socket_.reset(); | |
| 420 next_state_ = STATE_NONE; | |
| 421 } | |
| 422 | 416 |
| 423 void FtpNetworkTransaction::DoCallback(int rv) { | 417 DCHECK(!write_command_buf_); |
| 424 DCHECK(rv != ERR_IO_PENDING); | 418 DCHECK(!write_buf_); |
| 425 DCHECK(user_callback_); | |
| 426 | 419 |
| 427 // Since Run may result in Read being called, clear callback_ up front. | 420 if (!IsValidFTPCommandString(command)) { |
| 428 CompletionCallback* c = user_callback_; | 421 // Callers should validate the command themselves and return a more specific |
| 429 user_callback_ = NULL; | 422 // error code. |
| 430 c->Run(rv); | 423 NOTREACHED(); |
| 431 } | 424 return Stop(ERR_UNEXPECTED); |
| 425 } |
| 432 | 426 |
| 433 void FtpNetworkTransaction::OnIOComplete(int result) { | 427 command_sent_ = cmd; |
| 434 int rv = DoLoop(result); | 428 |
| 435 if (rv != ERR_IO_PENDING) | 429 write_command_buf_ = new IOBufferWithSize(command.length() + 2); |
| 436 DoCallback(rv); | 430 write_buf_ = new DrainableIOBuffer(write_command_buf_, |
| 431 write_command_buf_->size()); |
| 432 memcpy(write_command_buf_->data(), command.data(), command.length()); |
| 433 memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); |
| 434 |
| 435 next_state_ = STATE_CTRL_WRITE; |
| 436 return OK; |
| 437 } | 437 } |
| 438 | 438 |
| 439 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( | 439 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( |
| 440 bool is_directory) const { | 440 bool is_directory) const { |
| 441 std::string path(current_remote_directory_); | 441 std::string path(current_remote_directory_); |
| 442 if (request_->url.has_path()) { | 442 if (request_->url.has_path()) { |
| 443 std::string gurl_path(request_->url.path()); | 443 std::string gurl_path(request_->url.path()); |
| 444 | 444 |
| 445 // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. | 445 // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. |
| 446 std::string::size_type pos = gurl_path.rfind(';'); | 446 std::string::size_type pos = gurl_path.rfind(';'); |
| (...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 940 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 940 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
| 941 case ERROR_CLASS_PERMANENT_ERROR: | 941 case ERROR_CLASS_PERMANENT_ERROR: |
| 942 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 942 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
| 943 default: | 943 default: |
| 944 NOTREACHED(); | 944 NOTREACHED(); |
| 945 return Stop(ERR_UNEXPECTED); | 945 return Stop(ERR_UNEXPECTED); |
| 946 } | 946 } |
| 947 return OK; | 947 return OK; |
| 948 } | 948 } |
| 949 | 949 |
| 950 // SIZE command | |
| 951 int FtpNetworkTransaction::DoCtrlWriteSIZE() { | |
| 952 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); | |
| 953 next_state_ = STATE_CTRL_READ; | |
| 954 return SendFtpCommand(command, COMMAND_SIZE); | |
| 955 } | |
| 956 | |
| 957 int FtpNetworkTransaction::ProcessResponseSIZE( | |
| 958 const FtpCtrlResponse& response) { | |
| 959 switch (GetErrorClass(response.status_code)) { | |
| 960 case ERROR_CLASS_INITIATED: | |
| 961 break; | |
| 962 case ERROR_CLASS_OK: | |
| 963 if (response.lines.size() != 1) | |
| 964 return Stop(ERR_INVALID_RESPONSE); | |
| 965 int64 size; | |
| 966 if (!base::StringToInt64(response.lines[0], &size)) | |
| 967 return Stop(ERR_INVALID_RESPONSE); | |
| 968 if (size < 0) | |
| 969 return Stop(ERR_INVALID_RESPONSE); | |
| 970 | |
| 971 // A successful response to SIZE does not mean the resource is a file. | |
| 972 // Some FTP servers (for example, the qnx one) send a SIZE even for | |
| 973 // directories. | |
| 974 response_.expected_content_size = size; | |
| 975 break; | |
| 976 case ERROR_CLASS_INFO_NEEDED: | |
| 977 break; | |
| 978 case ERROR_CLASS_TRANSIENT_ERROR: | |
| 979 break; | |
| 980 case ERROR_CLASS_PERMANENT_ERROR: | |
| 981 // It's possible that SIZE failed because the path is a directory. | |
| 982 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && | |
| 983 response.status_code != 550) { | |
| 984 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | |
| 985 } | |
| 986 break; | |
| 987 default: | |
| 988 NOTREACHED(); | |
| 989 return Stop(ERR_UNEXPECTED); | |
| 990 } | |
| 991 | |
| 992 if (resource_type_ == RESOURCE_TYPE_FILE) | |
| 993 next_state_ = STATE_CTRL_WRITE_RETR; | |
| 994 else | |
| 995 next_state_ = STATE_CTRL_WRITE_CWD; | |
| 996 | |
| 997 return OK; | |
| 998 } | |
| 999 | |
| 1000 // RETR command | 950 // RETR command |
| 1001 int FtpNetworkTransaction::DoCtrlWriteRETR() { | 951 int FtpNetworkTransaction::DoCtrlWriteRETR() { |
| 1002 std::string command = "RETR " + GetRequestPathForFtpCommand(false); | 952 std::string command = "RETR " + GetRequestPathForFtpCommand(false); |
| 1003 next_state_ = STATE_CTRL_READ; | 953 next_state_ = STATE_CTRL_READ; |
| 1004 return SendFtpCommand(command, COMMAND_RETR); | 954 return SendFtpCommand(command, COMMAND_RETR); |
| 1005 } | 955 } |
| 1006 | 956 |
| 1007 int FtpNetworkTransaction::ProcessResponseRETR( | 957 int FtpNetworkTransaction::ProcessResponseRETR( |
| 1008 const FtpCtrlResponse& response) { | 958 const FtpCtrlResponse& response) { |
| 1009 switch (GetErrorClass(response.status_code)) { | 959 switch (GetErrorClass(response.status_code)) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1041 return Stop(ERR_UNEXPECTED); | 991 return Stop(ERR_UNEXPECTED); |
| 1042 } | 992 } |
| 1043 | 993 |
| 1044 // We should be sure about our resource type now. Otherwise we risk | 994 // We should be sure about our resource type now. Otherwise we risk |
| 1045 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). | 995 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). |
| 1046 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); | 996 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); |
| 1047 | 997 |
| 1048 return OK; | 998 return OK; |
| 1049 } | 999 } |
| 1050 | 1000 |
| 1001 // SIZE command |
| 1002 int FtpNetworkTransaction::DoCtrlWriteSIZE() { |
| 1003 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); |
| 1004 next_state_ = STATE_CTRL_READ; |
| 1005 return SendFtpCommand(command, COMMAND_SIZE); |
| 1006 } |
| 1007 |
| 1008 int FtpNetworkTransaction::ProcessResponseSIZE( |
| 1009 const FtpCtrlResponse& response) { |
| 1010 switch (GetErrorClass(response.status_code)) { |
| 1011 case ERROR_CLASS_INITIATED: |
| 1012 break; |
| 1013 case ERROR_CLASS_OK: |
| 1014 if (response.lines.size() != 1) |
| 1015 return Stop(ERR_INVALID_RESPONSE); |
| 1016 int64 size; |
| 1017 if (!base::StringToInt64(response.lines[0], &size)) |
| 1018 return Stop(ERR_INVALID_RESPONSE); |
| 1019 if (size < 0) |
| 1020 return Stop(ERR_INVALID_RESPONSE); |
| 1021 |
| 1022 // A successful response to SIZE does not mean the resource is a file. |
| 1023 // Some FTP servers (for example, the qnx one) send a SIZE even for |
| 1024 // directories. |
| 1025 response_.expected_content_size = size; |
| 1026 break; |
| 1027 case ERROR_CLASS_INFO_NEEDED: |
| 1028 break; |
| 1029 case ERROR_CLASS_TRANSIENT_ERROR: |
| 1030 break; |
| 1031 case ERROR_CLASS_PERMANENT_ERROR: |
| 1032 // It's possible that SIZE failed because the path is a directory. |
| 1033 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && |
| 1034 response.status_code != 550) { |
| 1035 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
| 1036 } |
| 1037 break; |
| 1038 default: |
| 1039 NOTREACHED(); |
| 1040 return Stop(ERR_UNEXPECTED); |
| 1041 } |
| 1042 |
| 1043 if (resource_type_ == RESOURCE_TYPE_FILE) |
| 1044 next_state_ = STATE_CTRL_WRITE_RETR; |
| 1045 else |
| 1046 next_state_ = STATE_CTRL_WRITE_CWD; |
| 1047 |
| 1048 return OK; |
| 1049 } |
| 1050 |
| 1051 // CWD command | 1051 // CWD command |
| 1052 int FtpNetworkTransaction::DoCtrlWriteCWD() { | 1052 int FtpNetworkTransaction::DoCtrlWriteCWD() { |
| 1053 std::string command = "CWD " + GetRequestPathForFtpCommand(true); | 1053 std::string command = "CWD " + GetRequestPathForFtpCommand(true); |
| 1054 next_state_ = STATE_CTRL_READ; | 1054 next_state_ = STATE_CTRL_READ; |
| 1055 return SendFtpCommand(command, COMMAND_CWD); | 1055 return SendFtpCommand(command, COMMAND_CWD); |
| 1056 } | 1056 } |
| 1057 | 1057 |
| 1058 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { | 1058 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { |
| 1059 // We should never issue CWD if we know the target resource is a file. | 1059 // We should never issue CWD if we know the target resource is a file. |
| 1060 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); | 1060 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1291 if (!had_error_type[type]) { | 1291 if (!had_error_type[type]) { |
| 1292 had_error_type[type] = true; | 1292 had_error_type[type] = true; |
| 1293 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", | 1293 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", |
| 1294 type, NUM_OF_NET_ERROR_TYPES); | 1294 type, NUM_OF_NET_ERROR_TYPES); |
| 1295 } | 1295 } |
| 1296 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", | 1296 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", |
| 1297 type, NUM_OF_NET_ERROR_TYPES); | 1297 type, NUM_OF_NET_ERROR_TYPES); |
| 1298 } | 1298 } |
| 1299 | 1299 |
| 1300 } // namespace net | 1300 } // namespace net |
| OLD | NEW |