@cappitolian/http-local-server-swifter 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -92,7 +92,7 @@ public protocol HttpLocalServerSwifterDelegate: AnyObject {
|
|
|
92
92
|
private func setupHandlers() {
|
|
93
93
|
guard let server = webServer else { return }
|
|
94
94
|
|
|
95
|
-
// Catch-all handler for all HTTP methods
|
|
95
|
+
// Catch-all handler for all HTTP methods and paths
|
|
96
96
|
server["/(.*)"] = { [weak self] request in
|
|
97
97
|
guard let self = self else {
|
|
98
98
|
return self?.errorResponse() ?? .internalServerError
|
|
@@ -168,7 +168,8 @@ public protocol HttpLocalServerSwifterDelegate: AnyObject {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
private func extractBody(from request: HttpRequest) -> String? {
|
|
171
|
-
guard let bodyBytes = request.body
|
|
171
|
+
guard let bodyBytes = request.body,
|
|
172
|
+
!bodyBytes.isEmpty else {
|
|
172
173
|
return nil
|
|
173
174
|
}
|
|
174
175
|
|
|
@@ -176,7 +177,8 @@ public protocol HttpLocalServerSwifterDelegate: AnyObject {
|
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
private func extractHeaders(from request: HttpRequest) -> [String: String] {
|
|
179
|
-
|
|
180
|
+
// Swifter's headers is [(String, String)]
|
|
181
|
+
return Dictionary(uniqueKeysWithValues: request.headers)
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
private func extractQuery(from request: HttpRequest) -> [String: String] {
|
|
@@ -184,44 +186,54 @@ public protocol HttpLocalServerSwifterDelegate: AnyObject {
|
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
private func createJsonResponse(_ body: String, statusCode: Int = 200) -> HttpResponse {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
switch statusCode {
|
|
190
|
-
case 200:
|
|
191
|
-
response = .ok(.text(body))
|
|
192
|
-
case 204:
|
|
193
|
-
response = HttpResponse.raw(204, "No Content", [:], nil)
|
|
194
|
-
case 408:
|
|
195
|
-
response = HttpResponse.raw(408, "Request Timeout", [:], { writer in
|
|
196
|
-
try writer.write([UInt8](body.utf8))
|
|
197
|
-
})
|
|
198
|
-
case 500:
|
|
199
|
-
response = .internalServerError
|
|
200
|
-
default:
|
|
201
|
-
response = HttpResponse.raw(statusCode, "Custom Status", [:], { writer in
|
|
202
|
-
try writer.write([UInt8](body.utf8))
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Add CORS headers
|
|
207
|
-
return response.withHeaders([
|
|
189
|
+
let headers: [String: String] = [
|
|
208
190
|
"Content-Type": "application/json",
|
|
209
191
|
"Access-Control-Allow-Origin": "*",
|
|
210
192
|
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
211
193
|
"Access-Control-Allow-Headers": "Origin, Content-Type, Accept, Authorization",
|
|
212
194
|
"Access-Control-Allow-Credentials": "true",
|
|
213
195
|
"Access-Control-Max-Age": "3600"
|
|
214
|
-
]
|
|
196
|
+
]
|
|
197
|
+
|
|
198
|
+
let bodyData = [UInt8](body.utf8)
|
|
199
|
+
|
|
200
|
+
return HttpResponse.raw(statusCode, statusDescription(for: statusCode), headers) { writer in
|
|
201
|
+
try writer.write(bodyData)
|
|
202
|
+
}
|
|
215
203
|
}
|
|
216
204
|
|
|
217
205
|
private func corsResponse() -> HttpResponse {
|
|
218
|
-
|
|
206
|
+
let headers: [String: String] = [
|
|
207
|
+
"Access-Control-Allow-Origin": "*",
|
|
208
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
209
|
+
"Access-Control-Allow-Headers": "Origin, Content-Type, Accept, Authorization",
|
|
210
|
+
"Access-Control-Allow-Credentials": "true",
|
|
211
|
+
"Access-Control-Max-Age": "3600"
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
return HttpResponse.raw(204, "No Content", headers, nil)
|
|
219
215
|
}
|
|
220
216
|
|
|
221
217
|
private func errorResponse() -> HttpResponse {
|
|
222
218
|
return createJsonResponse("{\"error\":\"Server error\"}", statusCode: 500)
|
|
223
219
|
}
|
|
224
220
|
|
|
221
|
+
private func statusDescription(for code: Int) -> String {
|
|
222
|
+
switch code {
|
|
223
|
+
case 200: return "OK"
|
|
224
|
+
case 201: return "Created"
|
|
225
|
+
case 202: return "Accepted"
|
|
226
|
+
case 204: return "No Content"
|
|
227
|
+
case 400: return "Bad Request"
|
|
228
|
+
case 401: return "Unauthorized"
|
|
229
|
+
case 403: return "Forbidden"
|
|
230
|
+
case 404: return "Not Found"
|
|
231
|
+
case 408: return "Request Timeout"
|
|
232
|
+
case 500: return "Internal Server Error"
|
|
233
|
+
default: return "Unknown"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
225
237
|
private func startServer() throws {
|
|
226
238
|
guard let server = webServer else {
|
|
227
239
|
throw NSError(
|
|
@@ -289,118 +301,4 @@ public protocol HttpLocalServerSwifterDelegate: AnyObject {
|
|
|
289
301
|
|
|
290
302
|
return address
|
|
291
303
|
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// MARK: - HttpResponse Extension
|
|
295
|
-
extension HttpResponse {
|
|
296
|
-
func withHeaders(_ headers: [String: String]) -> HttpResponse {
|
|
297
|
-
return HttpResponse.raw(self.statusCode(), self.reasonPhrase(), headers, { writer in
|
|
298
|
-
if let bodyData = try? self.content() {
|
|
299
|
-
try writer.write(bodyData)
|
|
300
|
-
}
|
|
301
|
-
})
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
func statusCode() -> Int {
|
|
305
|
-
switch self {
|
|
306
|
-
case .ok: return 200
|
|
307
|
-
case .created: return 201
|
|
308
|
-
case .accepted: return 202
|
|
309
|
-
case .movedPermanently: return 301
|
|
310
|
-
case .notModified: return 304
|
|
311
|
-
case .badRequest: return 400
|
|
312
|
-
case .unauthorized: return 401
|
|
313
|
-
case .forbidden: return 403
|
|
314
|
-
case .notFound: return 404
|
|
315
|
-
case .internalServerError: return 500
|
|
316
|
-
case .raw(let code, _, _, _): return code
|
|
317
|
-
default: return 200
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
func reasonPhrase() -> String {
|
|
322
|
-
switch self {
|
|
323
|
-
case .ok: return "OK"
|
|
324
|
-
case .created: return "Created"
|
|
325
|
-
case .accepted: return "Accepted"
|
|
326
|
-
case .movedPermanently: return "Moved Permanently"
|
|
327
|
-
case .notModified: return "Not Modified"
|
|
328
|
-
case .badRequest: return "Bad Request"
|
|
329
|
-
case .unauthorized: return "Unauthorized"
|
|
330
|
-
case .forbidden: return "Forbidden"
|
|
331
|
-
case .notFound: return "Not Found"
|
|
332
|
-
case .internalServerError: return "Internal Server Error"
|
|
333
|
-
case .raw(_, let phrase, _, _): return phrase
|
|
334
|
-
default: return "OK"
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
func content() throws -> [UInt8] {
|
|
339
|
-
switch self {
|
|
340
|
-
case .ok(let body), .created(let body), .accepted(let body):
|
|
341
|
-
return try bodyToBytes(body)
|
|
342
|
-
case .badRequest(let body), .notFound(let body), .internalServerError:
|
|
343
|
-
if let body = body {
|
|
344
|
-
return try bodyToBytes(body)
|
|
345
|
-
}
|
|
346
|
-
return []
|
|
347
|
-
case .raw(_, _, _, let writer):
|
|
348
|
-
var data = [UInt8]()
|
|
349
|
-
let mockWriter = MockResponseWriter { bytes in
|
|
350
|
-
data.append(contentsOf: bytes)
|
|
351
|
-
}
|
|
352
|
-
try writer?(mockWriter)
|
|
353
|
-
return data
|
|
354
|
-
default:
|
|
355
|
-
return []
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
private func bodyToBytes(_ body: HttpResponseBody) throws -> [UInt8] {
|
|
360
|
-
switch body {
|
|
361
|
-
case .text(let string):
|
|
362
|
-
return [UInt8](string.utf8)
|
|
363
|
-
case .html(let string):
|
|
364
|
-
return [UInt8](string.utf8)
|
|
365
|
-
case .json(let object):
|
|
366
|
-
let data = try JSONSerialization.data(withJSONObject: object)
|
|
367
|
-
return [UInt8](data)
|
|
368
|
-
case .data(let data, _):
|
|
369
|
-
return [UInt8](data)
|
|
370
|
-
case .custom(let writer):
|
|
371
|
-
var bytes = [UInt8]()
|
|
372
|
-
let mockWriter = MockResponseWriter { data in
|
|
373
|
-
bytes.append(contentsOf: data)
|
|
374
|
-
}
|
|
375
|
-
try writer(mockWriter)
|
|
376
|
-
return bytes
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// MARK: - Mock Response Writer
|
|
382
|
-
private class MockResponseWriter: HttpResponseBodyWriter {
|
|
383
|
-
let writeHandler: ([UInt8]) -> Void
|
|
384
|
-
|
|
385
|
-
init(writeHandler: @escaping ([UInt8]) -> Void) {
|
|
386
|
-
self.writeHandler = writeHandler
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
func write(_ data: [UInt8]) throws {
|
|
390
|
-
writeHandler(data)
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
func write(_ data: ArraySlice<UInt8>) throws {
|
|
394
|
-
writeHandler(Array(data))
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
func write(_ data: NSData) throws {
|
|
398
|
-
var bytes = [UInt8](repeating: 0, count: data.length)
|
|
399
|
-
data.getBytes(&bytes, length: data.length)
|
|
400
|
-
writeHandler(bytes)
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
func write(_ data: Data) throws {
|
|
404
|
-
writeHandler([UInt8](data))
|
|
405
|
-
}
|
|
406
304
|
}
|
|
@@ -7,7 +7,7 @@ import Capacitor
|
|
|
7
7
|
*/
|
|
8
8
|
@objc(HttpLocalServerSwifterPlugin)
|
|
9
9
|
public class HttpLocalServerSwifterPlugin: CAPPlugin, CAPBridgedPlugin, HttpLocalServerSwifterDelegate {
|
|
10
|
-
|
|
10
|
+
// MARK: - CAPBridgedPlugin Properties
|
|
11
11
|
public let identifier = "HttpLocalServerSwifterPlugin"
|
|
12
12
|
public let jsName = "HttpLocalServerSwifter"
|
|
13
13
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -16,8 +16,11 @@ public class HttpLocalServerSwifterPlugin: CAPPlugin, CAPBridgedPlugin, HttpLoca
|
|
|
16
16
|
CAPPluginMethod(name: "sendResponse", returnType: CAPPluginReturnPromise)
|
|
17
17
|
]
|
|
18
18
|
|
|
19
|
+
// MARK: - Properties
|
|
19
20
|
private var localServer: HttpLocalServerSwifter?
|
|
20
21
|
|
|
22
|
+
// MARK: - Plugin Methods
|
|
23
|
+
|
|
21
24
|
/**
|
|
22
25
|
* Starts the local HTTP server.
|
|
23
26
|
* @return ip: The server's IP address
|
|
@@ -62,6 +65,12 @@ public class HttpLocalServerSwifterPlugin: CAPPlugin, CAPBridgedPlugin, HttpLoca
|
|
|
62
65
|
call.resolve()
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
// MARK: - HttpLocalServerSwifterDelegate
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Delegate method called when the server receives an HTTP request.
|
|
72
|
+
* Notifies JavaScript via the 'onRequest' event.
|
|
73
|
+
*/
|
|
65
74
|
public func httpLocalServerSwifterDidReceiveRequest(_ data: [String: Any]) {
|
|
66
75
|
notifyListeners("onRequest", data: data)
|
|
67
76
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cappitolian/http-local-server-swifter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Runs a local HTTP server on your device, accessible over LAN. Supports connect, disconnect, GET, and POST methods with IP and port discovery.",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|