@cappitolian/http-local-server-swifter 0.0.3 → 0.0.5
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,60 +168,83 @@ public protocol HttpLocalServerSwifterDelegate: AnyObject {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
private func extractBody(from request: HttpRequest) -> String? {
|
|
171
|
-
|
|
171
|
+
// request.body ya es [UInt8], no es opcional
|
|
172
|
+
let bodyBytes = request.body
|
|
173
|
+
|
|
174
|
+
guard !bodyBytes.isEmpty else {
|
|
172
175
|
return nil
|
|
173
176
|
}
|
|
174
|
-
|
|
177
|
+
|
|
175
178
|
return String(bytes: bodyBytes, encoding: .utf8)
|
|
176
179
|
}
|
|
177
180
|
|
|
178
181
|
private func extractHeaders(from request: HttpRequest) -> [String: String] {
|
|
179
|
-
|
|
182
|
+
// Swifter headers es [(String, String)], convertir a [String: String]
|
|
183
|
+
var headersDict: [String: String] = [:]
|
|
184
|
+
for (key, value) in request.headers {
|
|
185
|
+
headersDict[key] = value
|
|
186
|
+
}
|
|
187
|
+
return headersDict
|
|
180
188
|
}
|
|
181
189
|
|
|
182
190
|
private func extractQuery(from request: HttpRequest) -> [String: String] {
|
|
183
|
-
|
|
191
|
+
// request.queryParams también es [(String, String)]
|
|
192
|
+
var queryDict: [String: String] = [:]
|
|
193
|
+
for (key, value) in request.queryParams {
|
|
194
|
+
queryDict[key] = value
|
|
195
|
+
}
|
|
196
|
+
return queryDict
|
|
184
197
|
}
|
|
185
198
|
|
|
186
199
|
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([
|
|
200
|
+
let headers: [String: String] = [
|
|
208
201
|
"Content-Type": "application/json",
|
|
209
202
|
"Access-Control-Allow-Origin": "*",
|
|
210
203
|
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
211
204
|
"Access-Control-Allow-Headers": "Origin, Content-Type, Accept, Authorization",
|
|
212
205
|
"Access-Control-Allow-Credentials": "true",
|
|
213
206
|
"Access-Control-Max-Age": "3600"
|
|
214
|
-
]
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
let bodyData = [UInt8](body.utf8)
|
|
210
|
+
|
|
211
|
+
return HttpResponse.raw(statusCode, statusDescription(for: statusCode), headers) { writer in
|
|
212
|
+
try writer.write(bodyData)
|
|
213
|
+
}
|
|
215
214
|
}
|
|
216
215
|
|
|
217
216
|
private func corsResponse() -> HttpResponse {
|
|
218
|
-
|
|
217
|
+
let headers: [String: String] = [
|
|
218
|
+
"Access-Control-Allow-Origin": "*",
|
|
219
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
220
|
+
"Access-Control-Allow-Headers": "Origin, Content-Type, Accept, Authorization",
|
|
221
|
+
"Access-Control-Allow-Credentials": "true",
|
|
222
|
+
"Access-Control-Max-Age": "3600"
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
return HttpResponse.raw(204, "No Content", headers, nil)
|
|
219
226
|
}
|
|
220
227
|
|
|
221
228
|
private func errorResponse() -> HttpResponse {
|
|
222
229
|
return createJsonResponse("{\"error\":\"Server error\"}", statusCode: 500)
|
|
223
230
|
}
|
|
224
231
|
|
|
232
|
+
private func statusDescription(for code: Int) -> String {
|
|
233
|
+
switch code {
|
|
234
|
+
case 200: return "OK"
|
|
235
|
+
case 201: return "Created"
|
|
236
|
+
case 202: return "Accepted"
|
|
237
|
+
case 204: return "No Content"
|
|
238
|
+
case 400: return "Bad Request"
|
|
239
|
+
case 401: return "Unauthorized"
|
|
240
|
+
case 403: return "Forbidden"
|
|
241
|
+
case 404: return "Not Found"
|
|
242
|
+
case 408: return "Request Timeout"
|
|
243
|
+
case 500: return "Internal Server Error"
|
|
244
|
+
default: return "Unknown"
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
225
248
|
private func startServer() throws {
|
|
226
249
|
guard let server = webServer else {
|
|
227
250
|
throw NSError(
|
|
@@ -289,118 +312,4 @@ public protocol HttpLocalServerSwifterDelegate: AnyObject {
|
|
|
289
312
|
|
|
290
313
|
return address
|
|
291
314
|
}
|
|
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
315
|
}
|
|
@@ -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.5",
|
|
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",
|