1/*
2 * Copyright 2022 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Niels Sascha Reedijk, niels.reedijk@gmail.com
7 */
8
9#include "HttpDebugLogger.h"
10
11#include <iostream>
12
13#include <ErrorsExt.h>
14#include <HttpSession.h>
15#include <NetServicesDefs.h>
16
17using namespace BPrivate::Network;
18
19
20HttpDebugLogger::HttpDebugLogger()
21	:
22	BLooper("HttpDebugLogger")
23{
24}
25
26
27void
28HttpDebugLogger::SetConsoleLogging(bool enabled)
29{
30	fConsoleLogging = enabled;
31}
32
33
34void
35HttpDebugLogger::SetFileLogging(const char* path)
36{
37	if (auto status = fLogFile.SetTo(path, B_WRITE_ONLY | B_CREATE_FILE | B_OPEN_AT_END);
38		status != B_OK)
39		throw BSystemError("BFile::SetTo()", status);
40}
41
42
43void
44HttpDebugLogger::MessageReceived(BMessage* message)
45{
46	BString output;
47
48	if (!message->HasInt32(UrlEventData::Id))
49		return BLooper::MessageReceived(message);
50	int32 id = message->FindInt32(UrlEventData::Id);
51	output << "[" << id << "] ";
52
53	switch (message->what) {
54		case UrlEvent::HostNameResolved:
55		{
56			BString hostname;
57			message->FindString(UrlEventData::HostName, &hostname);
58			output << "<HostNameResolved> " << hostname;
59			break;
60		}
61		case UrlEvent::ConnectionOpened:
62			output << "<ConnectionOpened>";
63			break;
64		case UrlEvent::UploadProgress:
65		{
66			off_t numBytes = message->GetInt64(UrlEventData::NumBytes, -1);
67			off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, -1);
68			output << "<UploadProgress> bytes uploaded " << numBytes;
69			if (totalBytes == -1)
70				output << " (total unknown)";
71			else
72				output << " (" << totalBytes << " total)";
73			break;
74		}
75		case UrlEvent::ResponseStarted:
76		{
77			output << "<ResponseStarted>";
78			break;
79		}
80		case UrlEvent::HttpRedirect:
81		{
82			BString redirectUrl;
83			message->FindString(UrlEventData::HttpRedirectUrl, &redirectUrl);
84			output << "<HttpRedirect> to: " << redirectUrl;
85			break;
86		}
87		case UrlEvent::HttpStatus:
88		{
89			int16 status = message->FindInt16(UrlEventData::HttpStatusCode);
90			output << "<HttpStatus> code: " << status;
91			break;
92		}
93		case UrlEvent::HttpFields:
94		{
95			output << "<HttpFields> All fields parsed";
96			break;
97		}
98		case UrlEvent::DownloadProgress:
99		{
100			off_t numBytes = message->GetInt64(UrlEventData::NumBytes, -1);
101			off_t totalBytes = message->GetInt64(UrlEventData::TotalBytes, -1);
102			output << "<DownloadProgress> bytes downloaded " << numBytes;
103			if (totalBytes == -1)
104				output << " (total unknown)";
105			else
106				output << " (" << totalBytes << " total)";
107			break;
108		}
109		case UrlEvent::BytesWritten:
110		{
111			off_t numBytes = message->GetInt64(UrlEventData::NumBytes, -1);
112			output << "<BytesWritten> bytes written to output: " << numBytes;
113			break;
114		}
115		case UrlEvent::RequestCompleted:
116		{
117			bool success = message->GetBool(UrlEventData::Success, false);
118			output << "<RequestCompleted> success: ";
119			if (success)
120				output << "true";
121			else
122				output << "false";
123			break;
124		}
125		case UrlEvent::DebugMessage:
126		{
127			uint32 debugType = message->GetUInt32(UrlEventData::DebugType, 0);
128			BString debugMessage;
129			message->FindString(UrlEventData::DebugMessage, &debugMessage);
130			output << "<DebugMessage> ";
131			switch (debugType) {
132				case UrlEventData::DebugInfo:
133					output << "INFO: ";
134					break;
135				case UrlEventData::DebugWarning:
136					output << "WARNING: ";
137					break;
138				case UrlEventData::DebugError:
139					output << "ERROR: ";
140					break;
141				default:
142					output << "UNKNOWN: ";
143					break;
144			}
145			output << debugMessage;
146			break;
147		}
148		default:
149			return BLooper::MessageReceived(message);
150	}
151
152	if (fConsoleLogging)
153		std::cout << output.String() << std::endl;
154
155	if (fLogFile.InitCheck() == B_OK) {
156		output += '\n';
157		if (auto status = fLogFile.WriteExactly(output.String(), output.Length()); status != B_OK)
158			throw BSystemError("BFile::WriteExactly()", status);
159		if (auto status = fLogFile.Flush(); status != B_OK)
160			throw BSystemError("BFile::Flush()", status);
161	}
162}
163