status_t
BHttpRequest::_ProtocolLoop()
{
	// Initialize the request redirection loop
	int8 maxRedirs = fOptMaxRedirs;
	bool newRequest;

	do {
		newRequest = false;

		// Result reset
		fHeaders.Clear();
		_ResultHeaders().Clear();

		BString host = fUrl.Host();
		int port = fSSL ? 443 : 80;

		if (fUrl.HasPort())
			port = fUrl.Port();

		if (fContext->UseProxy()) {
			host = fContext->GetProxyHost();
			port = fContext->GetProxyPort();
		}

		status_t result = fInputBuffer.InitCheck();
		if (result != B_OK)
			return result;

		if (!_ResolveHostName(host, port)) {
			_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
				"Unable to resolve hostname (%s), aborting.",
					fUrl.Host().String());
			return B_SERVER_NOT_FOUND;
		}

		status_t requestStatus = _MakeRequest();
		if (requestStatus != B_OK)
			return requestStatus;

		// Prepare the referer for the next request if needed
		if (fOptAutoReferer)
			fOptReferer = fUrl.UrlString();

		switch (StatusCodeClass(fResult.StatusCode())) {
			case B_HTTP_STATUS_CLASS_INFORMATIONAL:
				// Header 100:continue should have been
				// handled in the _MakeRequest read loop
				break;

			case B_HTTP_STATUS_CLASS_SUCCESS:
				break;

			case B_HTTP_STATUS_CLASS_REDIRECTION:
			{
				// Redirection has been explicitly disabled
				if (!fOptFollowLocation)
					break;

				int code = fResult.StatusCode();
				if (code == B_HTTP_STATUS_MOVED_PERMANENTLY
					|| code == B_HTTP_STATUS_FOUND
					|| code == B_HTTP_STATUS_SEE_OTHER
					|| code == B_HTTP_STATUS_TEMPORARY_REDIRECT) {
					BString locationUrl = fHeaders["Location"];

					fUrl = BUrl(fUrl, locationUrl);

					// 302 and 303 redirections also convert POST requests to GET
					// (and remove the posted form data)
					if ((code == B_HTTP_STATUS_FOUND
						|| code == B_HTTP_STATUS_SEE_OTHER)
						&& fRequestMethod == B_HTTP_POST) {
						SetMethod(B_HTTP_GET);
						delete fOptPostFields;
						fOptPostFields = NULL;
						delete fOptInputData;
						fOptInputData = NULL;
						fOptInputDataSize = 0;
					}

					if (--maxRedirs > 0) {
						newRequest = true;

						// Redirections may need a switch from http to https.
						if (fUrl.Protocol() == "https")
							fSSL = true;
						else if (fUrl.Protocol() == "http")
							fSSL = false;

						_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT,
							"Following: %s\n",
							fUrl.UrlString().String());
					}
				}
				break;
			}

			case B_HTTP_STATUS_CLASS_CLIENT_ERROR:
				if (fResult.StatusCode() == B_HTTP_STATUS_UNAUTHORIZED) {
					BHttpAuthentication* authentication
						= &fContext->GetAuthentication(fUrl);
					status_t status = B_OK;

					if (authentication->Method() == B_HTTP_AUTHENTICATION_NONE) {
						// There is no authentication context for this
						// url yet, so let's create one.
						BHttpAuthentication newAuth;
						newAuth.Initialize(fHeaders["WWW-Authenticate"]);
						fContext->AddAuthentication(fUrl, newAuth);

						// Get the copy of the authentication we just added.
						// That copy is owned by the BUrlContext and won't be
						// deleted (unlike the temporary object above)
						authentication = &fContext->GetAuthentication(fUrl);
					}

					newRequest = false;
					if (fOptUsername.Length() > 0 && status == B_OK) {
						// If we received an username and password, add them
						// to the request. This will either change the
						// credentials for an existing request, or set them
						// for a new one we created just above.
						//
						// If this request handles HTTP redirections, it will
						// also automatically retry connecting and send the
						// login information.
						authentication->SetUserName(fOptUsername);
						authentication->SetPassword(fOptPassword);
						newRequest = true;
					}
				}
				break;

			case B_HTTP_STATUS_CLASS_SERVER_ERROR:
				break;

			default:
			case B_HTTP_STATUS_CLASS_INVALID:
				break;
		}
	} while (newRequest);

	_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT,
		"%ld headers and %ld bytes of data remaining",
		fHeaders.CountHeaders(), fInputBuffer.Size());

	if (fResult.StatusCode() == 404)
		return B_RESOURCE_NOT_FOUND;

	return B_OK;
}
Exemple #2
0
status_t
BHttpRequest::_ProtocolLoop()
{
	// Initialize the request redirection loop
	int8 maxRedirs = fOptMaxRedirs;
	bool newRequest;

	do {
		newRequest = false;

		// Result reset
		fOutputHeaders.Clear();
		fHeaders.Clear();
		_ResultHeaders().Clear();

		if (!_ResolveHostName()) {
			_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
				"Unable to resolve hostname (%s), aborting.",
					fUrl.Host().String());
			return B_SERVER_NOT_FOUND;
		}

		status_t requestStatus = _MakeRequest();
		if (requestStatus != B_OK)
			return requestStatus;

		// Prepare the referer for the next request if needed
		if (fOptAutoReferer)
			fOptReferer = fUrl.UrlString();

		switch (StatusCodeClass(fResult.StatusCode())) {
			case B_HTTP_STATUS_CLASS_INFORMATIONAL:
				// Header 100:continue should have been
				// handled in the _MakeRequest read loop
				break;

			case B_HTTP_STATUS_CLASS_SUCCESS:
				break;

			case B_HTTP_STATUS_CLASS_REDIRECTION:
				// Redirection has been explicitly disabled
				if (!fOptFollowLocation)
					break;

				//  TODO: Some browsers seems to translate POST requests to
				// GET when following a 302 redirection
				if (fResult.StatusCode() == B_HTTP_STATUS_MOVED_PERMANENTLY) {
					BString locationUrl = fHeaders["Location"];

					fUrl = BUrl(fUrl, locationUrl);

					if (--maxRedirs > 0) {
						newRequest = true;

						_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT,
							"Following: %s\n",
							fUrl.UrlString().String());
					}
				}
				break;

			case B_HTTP_STATUS_CLASS_CLIENT_ERROR:
				if (fResult.StatusCode() == B_HTTP_STATUS_UNAUTHORIZED) {
					BHttpAuthentication* authentication
						= &fContext->GetAuthentication(fUrl);
					status_t status = B_OK;

					if (authentication->Method() == B_HTTP_AUTHENTICATION_NONE) {
						// There is no authentication context for this
						// url yet, so let's create one.
						authentication
							= new(std::nothrow) BHttpAuthentication();
						if (authentication == NULL)
							status = B_NO_MEMORY;
						else {
							status = authentication->Initialize(
								fHeaders["WWW-Authenticate"]);
							fContext->AddAuthentication(fUrl, authentication);
						}
					}

					newRequest = false;
					if (fOptUsername.Length() > 0 && status == B_OK) {
						// If we received an username and password, add them
						// to the request. This will either change the
						// credentials for an existing request, or set them
						// for a new one we created just above.
						//
						// If this request handles HTTP redirections, it will
						// also automatically retry connecting and send the
						// login information.
						authentication->SetUserName(fOptUsername);
						authentication->SetPassword(fOptPassword);
						newRequest = true;
					}
				}
				break;

			case B_HTTP_STATUS_CLASS_SERVER_ERROR:
				break;

			default:
			case B_HTTP_STATUS_CLASS_INVALID:
				break;
		}
	} while (newRequest);

	_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT,
		"%ld headers and %ld bytes of data remaining",
		fHeaders.CountHeaders(), fInputBuffer.Size());

	if (fResult.StatusCode() == 404)
		return B_RESOURCE_NOT_FOUND;

	return B_OK;
}