Initial project setup - Phases 1-3 complete
This commit is contained in:
106
ProxyCore/Sources/Shared/CURLParser.swift
Normal file
106
ProxyCore/Sources/Shared/CURLParser.swift
Normal file
@@ -0,0 +1,106 @@
|
||||
import Foundation
|
||||
|
||||
public struct ParsedCURLRequest: Sendable {
|
||||
public var method: String = "GET"
|
||||
public var url: String = ""
|
||||
public var headers: [(key: String, value: String)] = []
|
||||
public var body: String?
|
||||
}
|
||||
|
||||
public enum CURLParser {
|
||||
public static func parse(_ curlString: String) -> ParsedCURLRequest? {
|
||||
var result = ParsedCURLRequest()
|
||||
let trimmed = curlString.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
guard trimmed.lowercased().hasPrefix("curl") else { return nil }
|
||||
|
||||
let tokens = tokenize(trimmed)
|
||||
var i = 0
|
||||
|
||||
while i < tokens.count {
|
||||
let token = tokens[i]
|
||||
|
||||
switch token {
|
||||
case "curl":
|
||||
break
|
||||
case "-X", "--request":
|
||||
i += 1
|
||||
if i < tokens.count {
|
||||
result.method = tokens[i].uppercased()
|
||||
}
|
||||
case "-H", "--header":
|
||||
i += 1
|
||||
if i < tokens.count {
|
||||
let header = tokens[i]
|
||||
if let colonIndex = header.firstIndex(of: ":") {
|
||||
let key = String(header[header.startIndex..<colonIndex]).trimmingCharacters(in: .whitespaces)
|
||||
let value = String(header[header.index(after: colonIndex)...]).trimmingCharacters(in: .whitespaces)
|
||||
result.headers.append((key: key, value: value))
|
||||
}
|
||||
}
|
||||
case "-d", "--data", "--data-raw", "--data-binary":
|
||||
i += 1
|
||||
if i < tokens.count {
|
||||
result.body = tokens[i]
|
||||
if result.method == "GET" {
|
||||
result.method = "POST"
|
||||
}
|
||||
}
|
||||
default:
|
||||
if !token.hasPrefix("-") && result.url.isEmpty {
|
||||
result.url = token
|
||||
}
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
|
||||
return result.url.isEmpty ? nil : result
|
||||
}
|
||||
|
||||
private static func tokenize(_ input: String) -> [String] {
|
||||
var tokens: [String] = []
|
||||
var current = ""
|
||||
var inSingleQuote = false
|
||||
var inDoubleQuote = false
|
||||
var escaped = false
|
||||
|
||||
for char in input {
|
||||
if escaped {
|
||||
current.append(char)
|
||||
escaped = false
|
||||
continue
|
||||
}
|
||||
|
||||
if char == "\\" && !inSingleQuote {
|
||||
escaped = true
|
||||
continue
|
||||
}
|
||||
|
||||
if char == "'" && !inDoubleQuote {
|
||||
inSingleQuote.toggle()
|
||||
continue
|
||||
}
|
||||
|
||||
if char == "\"" && !inSingleQuote {
|
||||
inDoubleQuote.toggle()
|
||||
continue
|
||||
}
|
||||
|
||||
if char.isWhitespace && !inSingleQuote && !inDoubleQuote {
|
||||
if !current.isEmpty {
|
||||
tokens.append(current)
|
||||
current = ""
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
current.append(char)
|
||||
}
|
||||
|
||||
if !current.isEmpty {
|
||||
tokens.append(current)
|
||||
}
|
||||
|
||||
return tokens
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user