Create dedicate crate for php_escaping.rs
[hiphop-php.git] / hphp / runtime / server / log-writer.h
blobe5f96a451382375f156011e7ceeba4cd5210d43d
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_LOG_WRITER_H_
17 #define incl_HPHP_LOG_WRITER_H_
19 #include <string>
21 #include <folly/Conv.h>
22 #include <folly/Format.h>
24 #include "hphp/runtime/base/timestamp.h"
25 #include "hphp/runtime/server/access-log.h"
26 #include "hphp/runtime/server/http-server.h"
27 #include "hphp/runtime/server/request-uri.h"
28 #include "hphp/runtime/server/server-note.h"
29 #include "hphp/runtime/server/server-stats.h"
30 #include "hphp/runtime/server/server.h"
31 #include "hphp/runtime/server/transport.h"
32 #include "hphp/runtime/server/virtual-host.h"
33 #include "hphp/util/hardware-counter.h"
34 #include "hphp/util/timer.h"
35 #include "hphp/util/service-data.h"
37 namespace HPHP {
38 ///////////////////////////////////////////////////////////////////////////////
40 struct ClassicWriter final : LogWriter {
41 ClassicWriter(const AccessLogFileData& alfd, LogChannel chan)
42 : LogWriter(chan)
43 , m_logdata(alfd)
45 ~ClassicWriter() override;
46 void init(const std::string& username,
47 AccessLog::GetThreadDataFunc fn) override;
48 void write(Transport* transport, const VirtualHost* vhost) override;
49 const static std::string handle;
50 private:
51 const AccessLogFileData m_logdata;
52 static bool parseConditions(const char*& fmt, int code);
53 static std::string parseArgument(const char*& fmt);
54 static void skipField(const char*& fmt);
57 struct FieldGenerator {
58 FieldGenerator(Transport* t, const VirtualHost* vh,
59 AccessLog::ThreadData* tdata)
60 : transport(t)
61 , vhost(vh)
62 , threadData(tdata)
64 template<typename T>
65 bool gen(char field, const std::string& arg, T& out);
66 private:
67 static std::string escapeData(const char* s, int len);
68 Transport* transport;
69 const VirtualHost* vhost;
70 AccessLog::ThreadData* threadData;
73 template<typename T>
74 bool FieldGenerator::gen(char field, const std::string& arg, T& out) {
75 int responseSize = transport->getResponseSize();
76 int code = transport->getResponseCode();
78 switch (field) {
79 case 'b':
80 if (responseSize == 0) return false;
81 // Fall through
82 case 'B':
83 out = folly::to<T>(responseSize);
84 break;
85 case 'c':
87 if (arg.empty()) return false;
88 std::string config = IniSetting::Get(arg);
89 if (config.empty()) return false;
90 out = folly::to<T>(config);
92 break;
93 case 'C':
95 if (arg.empty()) return false;
96 std::string cookie = transport->getCookie(arg);
97 if (cookie.empty()) return false;
98 out = folly::to<T>(escapeData(cookie.c_str(), cookie.size()));
100 break;
101 case 'D':
103 struct timespec now;
104 Timer::GetMonotonicTime(now);
105 out = folly::to<T>(gettime_diff_us(transport->getWallTime(), now));
107 break;
108 case 'd':
110 #ifdef CLOCK_THREAD_CPUTIME_ID
111 struct timespec now;
112 gettime(CLOCK_THREAD_CPUTIME_ID, &now);
113 out = folly::to<T>(gettime_diff_us(transport->getCpuTime(), now));
114 #else
115 return false;
116 #endif
118 break;
119 case 'h':
121 std::string host = transport->getRemoteHost();
122 if (host.empty()) host = transport->getRemoteAddr();
123 out = folly::to<T>(host);
125 break;
126 case 'H':
127 if (arg.empty()) return false;
128 out = folly::to<T>(ServerStats::Get(arg));
129 break;
130 case 'i':
132 if (arg.empty()) return false;
133 std::string header = transport->getHeader(arg.c_str());
134 if (header.empty()) return false;
135 if (vhost && vhost->hasLogFilter() &&
136 strcasecmp(arg.c_str(), "Referer") == 0) {
137 out = folly::to<T>(vhost->filterUrl(header));
138 } else {
139 out = folly::to<T>(header);
142 break;
143 case 'I':
144 out = folly::to<T>(transport->getRequestSize());
145 break;
146 case 'j':
148 auto static jitMaturityCounter =
149 ServiceData::createCounter("jit.maturity");
150 if (jitMaturityCounter) {
151 out = folly::to<T>(jitMaturityCounter->getValue());
154 break;
155 case 'n':
156 if (arg.empty()) return false;
158 String note = ServerNote::Get(arg);
159 if (note.isNull()) return false;
160 out = folly::to<T>(note.data());
162 break;
163 case 'o':
164 out = folly::to<T>(ServerStats::Get("request.memory_exceeded.non_psp"));
165 break;
166 case 'O':
167 out = folly::to<T>(ServerStats::Get("request.memory_exceeded.psp"));
168 break;
169 case 'p':
170 out = folly::to<T>(ServerStats::Get("request.timed_out.non_psp"));
171 break;
172 case 'P':
173 out = folly::to<T>(ServerStats::Get("request.timed_out.psp"));
174 break;
175 case 'r':
177 const char *method = transport->getMethodName();
178 if (!method || !method[0]) return false;
179 const char *url = transport->getUrl();
180 out = folly::to<T>(folly::sformat(
181 "{} {} HTTP/{}", method,
182 (vhost && vhost->hasLogFilter()) ? vhost->filterUrl(url) : url,
183 transport->getHTTPVersion()
186 break;
187 case 's':
188 out = folly::to<T>(code);
189 break;
190 case 'S':
191 // %S is not defined in Apache, we grab it here
193 const std::string& info(transport->getResponseInfo());
194 if (info.empty()) return false;
195 out = folly::to<T>(info);
197 break;
198 case 't':
200 const char *fmt = arg.empty() ? "[%d/%b/%Y:%H:%M:%S %z]" : arg.c_str();
201 char buf[256];
202 time_t rawtime;
203 struct tm timeinfo;
204 time(&rawtime);
205 localtime_r(&rawtime, &timeinfo);
206 strftime(buf, 256, fmt, &timeinfo);
207 out = folly::to<T>(buf);
209 break;
210 case 'T':
211 out = folly::to<T>(threadData ?
212 TimeStamp::Current() - threadData->startTime : 0);
213 break;
214 case 'U':
216 String b, q;
217 RequestURI::splitURL(transport->getUrl(), b, q);
218 out = folly::to<T>(b.c_str());
220 break;
221 case 'w':
222 // server uptime
223 out = folly::to<T>(TimeStamp::Current() - HttpServer::StartTime);
224 break;
225 case 'v':
227 std::string host = transport->getHeader("Host");
228 const std::string &sname = VirtualHost::GetCurrent()->serverName(host);
229 if (sname.empty() || RuntimeOption::ForceServerNameToHeader) {
230 out = folly::to<T>(host);
231 } else {
232 out = folly::to<T>(sname);
235 break;
236 case 'Y':
238 int64_t now = HardwareCounter::GetInstructionCount();
239 out = folly::to<T>(now - transport->getInstructions());
241 break;
242 case 'y':
243 out = folly::to<T>(ServerStats::Get("page.inst.psp"));
244 break;
245 case 'Z':
246 out = folly::to<T>(ServerStats::Get("page.wall.psp"));
247 break;
248 case 'z':
249 out = folly::to<T>(ServerStats::Get("page.cpu.psp"));
250 break;
251 default:
252 return false;
254 return true;
257 ///////////////////////////////////////////////////////////////////////////////
260 #endif // incl_HPHP_LOG_WRITER_H_