Skip to content

Commit a7949f9

Browse files
authored
Merge pull request #353 from HapticX/dev
improve server answer speed
2 parents 200a174 + 85e5eb9 commit a7949f9

File tree

4 files changed

+178
-25
lines changed

4 files changed

+178
-25
lines changed

happyx.nimble

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
description = "Macro-oriented asynchronous web-framework written with ♥"
44
author = "HapticX"
5-
version = "4.6.0"
5+
version = "4.6.1"
66
license = "MIT"
77
srcDir = "src"
88
installExt = @["nim"]

src/happyx/core/constants.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ const
107107
# Framework version
108108
HpxMajor* = 4
109109
HpxMinor* = 6
110-
HpxPatch* = 0
110+
HpxPatch* = 1
111111
HpxVersion* = $HpxMajor & "." & $HpxMinor & "." & $HpxPatch
112112

113113

src/happyx/ssr/cors.nim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ type
2929
allowMethods*: string
3030

3131

32+
const corsRegistered* = CacheCounter"HappyXCORSRegistered"
33+
34+
3235

3336
when not defined(js) and not (exportJvm or exportPython or defined(napibuild)):
3437
var currentCORS {. compileTime .} = CORSObj()
@@ -81,6 +84,7 @@ when not defined(js) and not (exportJvm or exportPython or defined(napibuild)):
8184
else:
8285
result.add quote do:
8386
`headers`["Access-Control-Allow-Origin"] = `allowOrigins`
87+
inc corsRegistered
8488

8589
macro regCORS*(body: untyped): untyped =
8690
## Register CORS

src/happyx/ssr/server.nim

Lines changed: 172 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,125 @@ macro `.`*(obj: JsonNode, field: untyped): JsonNode =
246246
newCall("[]", obj, newLit($field.toStrLit))
247247
248248
249+
const defaultHeaders = "Content-Type: text/plain;charset=utf-8"
250+
251+
249252
template answer*(
250253
req: Request,
251254
message: string | int | float | bool | char,
252-
code: HttpCode = Http200,
253-
headers: HttpHeaders = newHttpHeaders([
255+
code: HttpCode = Http200
256+
) =
257+
## Answers to the request
258+
##
259+
## ⚠ `Low-level API` ⚠
260+
##
261+
## Arguments:
262+
## `req: Request`: An instance of the Request type, representing the request that we are responding to.
263+
## `message: string`: The message that we want to include in the response body.
264+
## `code: HttpCode = Http200`: The HTTP status code that we want to send in the response.
265+
## This argument is optional, with a default value of Http200 (OK).
266+
##
267+
## Use this example instead
268+
##
269+
## .. code-block::nim
270+
## get "/":
271+
## return "Hello, world!"
272+
##
273+
const useHeaders = declared(outHeaders) or declared(outCookies) or corsRegistered.value > 0
274+
when useHeaders:
275+
var h = newHttpHeaders([
254276
("Content-Type", "text/plain; charset=utf-8")
255-
]),
277+
])
278+
when corsRegistered.value > 0:
279+
when exportJvm or exportPython or defined(napibuild):
280+
when enableHttpBeast or enableHttpx:
281+
addCORSHeaders(req.ip, h)
282+
else:
283+
addCORSHeaders(req.hostname, h)
284+
else:
285+
h.addCORSHeaders()
286+
when declared(outHeaders):
287+
for key, val in outHeaders.pairs():
288+
h[key] = val
289+
# HTTPX
290+
when enableHttpx:
291+
when useHeaders:
292+
var headersArr = ""
293+
for key, value in h.pairs():
294+
headersArr &= key & ':' & value & "\r\n"
295+
when declared(outCookies):
296+
for cookie in outCookies:
297+
headersArr &= cookie & "\r\n"
298+
if headersArr.len > 0:
299+
headersArr.delete(headersArr.len-2..headersArr.len-1)
300+
301+
# check safety requests
302+
when enableSafeRequests:
303+
when declared(statusCode):
304+
when statusCode is int:
305+
req.send(statusCode.HttpCode, $message, when useHeaders: headersArr else: defaultHeaders)
306+
else:
307+
req.send(code, $message, when useHeaders: headersArr else: defaultHeaders)
308+
else:
309+
req.send(code, $message, when useHeaders: headersArr else: defaultHeaders)
310+
else:
311+
# Use unsafeSend to improve speed
312+
var data: string = "HTTP/1.1 "
313+
when declared(statusCode):
314+
when statusCode is int:
315+
data &= $statusCode
316+
else:
317+
data &= $code
318+
else:
319+
data &= $code
320+
when message is string:
321+
data &= "\c\LContent-Length:" & $len(message)
322+
data &= "\c\L" & (when useHeaders: headersArr else: defaultHeaders) & "\c\L\c\L" & message
323+
else:
324+
data &= "\c\LContent-Length:" & $len($message)
325+
data &= "\c\L" & (when useHeaders: headersArr else: defaultHeaders) & "\c\L\c\L" & $message
326+
req.unsafeSend(data)
327+
# HTTP BEAST
328+
elif enableHttpBeast:
329+
when useHeaders:
330+
var headersArr = ""
331+
for key, value in h.pairs():
332+
headersArr &= key & ':' & value & "\r\n"
333+
when declared(outCookies):
334+
for cookie in outCookies:
335+
headersArr &= cookie & "\r\n"
336+
if headersArr.len > 0:
337+
headersArr.delete(headersArr.len-2..headersArr.len-1)
338+
when declared(statusCode):
339+
when statusCode is int:
340+
req.send(statusCode.HttpCode, $message, when useHeaders: headersArr else: defaultHeaders)
341+
else:
342+
req.send(code, $message, when useHeaders: headersArr else: defaultHeaders)
343+
else:
344+
req.send(code, $message, when useHeaders: headersArr else: defaultHeaders)
345+
# ASYNC HTTP SERVER / MICRO ASYNC HTTP SERVER
346+
else:
347+
when useHeaders:
348+
when declared(outCookies):
349+
for cookie in outCookies:
350+
let data = cookie.split(":", 1)
351+
h.add("Set-Cookie", data[1].strip())
352+
else:
353+
let h = newHttpHeaders([("Content-Type", "text/plain;charset=utf-8")])
354+
when declared(statusCode):
355+
when statusCode is int:
356+
await req.respond(statusCode.HttpCode, $message, h)
357+
else:
358+
await req.respond(code, $message, h)
359+
else:
360+
await req.respond(code, $message, h)
361+
362+
363+
template answer*(
364+
req: Request,
365+
message: string | int | float | bool | char,
366+
code: HttpCode = Http200,
367+
headers: HttpHeaders,
256368
contentLength: Option[int] = int.none
257369
) =
258370
## Answers to the request
@@ -272,43 +384,80 @@ template answer*(
272384
## return "Hello, world!"
273385
##
274386
var h = headers
275-
when exportJvm or exportPython or defined(napibuild):
276-
when enableHttpBeast or enableHttpx:
277-
addCORSHeaders(req.ip, h)
387+
when corsRegistered.value > 0:
388+
when exportJvm or exportPython or defined(napibuild):
389+
when enableHttpBeast or enableHttpx:
390+
addCORSHeaders(req.ip, h)
391+
else:
392+
addCORSHeaders(req.hostname, h)
278393
else:
279-
addCORSHeaders(req.hostname, h)
280-
else:
281-
h.addCORSHeaders()
394+
h.addCORSHeaders()
282395
when declared(outHeaders):
283396
for key, val in outHeaders.pairs():
284397
h[key] = val
285398
# HTTPX
286399
when enableHttpx:
287400
var headersArr = ""
288401
for key, value in h.pairs():
289-
headersArr &= key & ':' & value & "\r\n"
402+
headersArr &= key & ':' & value & "\c\L"
290403
when declared(outCookies):
291404
for cookie in outCookies:
292-
headersArr &= cookie & "\r\n"
405+
headersArr &= cookie & "\c\L"
293406
if headersArr.len > 0:
294-
headersArr = headersArr[0..^3]
407+
headersArr.delete(headersArr.len-2..headersArr.len-1)
295408
if contentLength.isSome:
296409
# useful for file answers
297-
when declared(statusCode):
298-
when statusCode is int:
299-
req.send(statusCode.HttpCode, $message, contentLength, headersArr)
410+
when enableSafeRequests:
411+
when declared(statusCode):
412+
when statusCode is int:
413+
req.send(statusCode.HttpCode, $message, contentLength, headersArr)
414+
else:
415+
req.send(code, $message, contentLength, headersArr)
300416
else:
301417
req.send(code, $message, contentLength, headersArr)
302418
else:
303-
req.send(code, $message, contentLength, headersArr)
419+
# Use unsafeSend to improve speed
420+
var data: string = "HTTP/1.1 "
421+
when declared(statusCode):
422+
when statusCode is int:
423+
data &= $statusCode
424+
else:
425+
data &= $code
426+
else:
427+
data &= $code
428+
when message is string:
429+
data &= "\c\LContent-Length:" & $contentLength.get()
430+
data &= "\c\L" & headersArr & "\c\L\c\L" & message
431+
else:
432+
data &= "\c\LContent-Length:" & $contentLength.get()
433+
data &= "\c\L" & headersArr & "\c\L\c\L" & $message
434+
req.unsafeSend(data)
304435
else:
305-
when declared(statusCode):
306-
when statusCode is int:
307-
req.send(statusCode.HttpCode, $message, headersArr)
436+
when enableSafeRequests:
437+
when declared(statusCode):
438+
when statusCode is int:
439+
req.send(statusCode.HttpCode, $message, headersArr)
440+
else:
441+
req.send(code, $message, headersArr)
308442
else:
309443
req.send(code, $message, headersArr)
310444
else:
311-
req.send(code, $message, headersArr)
445+
# Use unsafeSend to improve speed
446+
var data: string = "HTTP/1.1 "
447+
when declared(statusCode):
448+
when statusCode is int:
449+
data &= $statusCode
450+
else:
451+
data &= $code
452+
else:
453+
data &= $code
454+
when message is string:
455+
data &= "\c\LContent-Length:" & $len(message)
456+
data &= "\c\L" & headersArr & "\c\L\c\L" & message
457+
else:
458+
data &= "\c\LContent-Length:" & $len($message)
459+
data &= "\c\L" & headersArr & "\c\L\c\L" & $message
460+
req.unsafeSend(data)
312461
# HTTP BEAST
313462
elif enableHttpBeast:
314463
var headersArr = ""
@@ -318,7 +467,7 @@ template answer*(
318467
for cookie in outCookies:
319468
headersArr &= cookie & "\r\n"
320469
if headersArr.len > 0:
321-
headersArr = headersArr[0..^3]
470+
headersArr.delete(headersArr.len-2..headersArr.len-1)
322471
when declared(statusCode):
323472
when statusCode is int:
324473
req.send(statusCode.HttpCode, $message, headersArr)
@@ -347,7 +496,7 @@ when enableHttpBeast:
347496

348497

349498
template answerJson*(req: Request, data: untyped, code: HttpCode = Http200,
350-
headers: HttpHeaders = newHttpHeaders([("Content-Type", "application/json; charset=utf-8")])): untyped =
499+
headers: HttpHeaders = newHttpHeaders([("Content-Type", "application/json;charset=utf-8")])): untyped =
351500
## Answers to request with json data
352501
##
353502
## ⚠ `Low-level API` ⚠
@@ -368,7 +517,7 @@ template answerJson*(req: Request, data: untyped, code: HttpCode = Http200,
368517

369518

370519
template answerHtml*(req: Request, data: string | TagRef, code: HttpCode = Http200,
371-
headers: HttpHeaders = newHttpHeaders([("Content-Type", "text/html; charset=utf-8")])): untyped =
520+
headers: HttpHeaders = newHttpHeaders([("Content-Type", "text/html;charset=utf-8")])): untyped =
372521
## Answers to request with HTML data
373522
##
374523
## ⚠ `Low-level API` ⚠

0 commit comments

Comments
 (0)