F# と FParsec を使用してマルチパート MIME パーサーを開発しています。私は繰り返し開発しているので、これは非常に洗練されていない、もろいコードです。これは、私の最初の問題を解決するだけです。赤、緑、リファクタリング。
文字列ではなくストリームを解析する必要があるため、実際にループに陥っています。その制約を考えると、私の理解では、パーサーを再帰的に呼び出す必要があります。それを行う方法は、少なくとも私がこれまで進めてきた方法では、私の理解を超えています.
namespace MultipartMIMEParser
open FParsec
open System.IO
type private Post = { contentType : string
; boundary : string
; subtype : string
; content : string }
type MParser (s:Stream) =
let ($) f x = f x
let ascii = System.Text.Encoding.ASCII
let str cs = System.String.Concat (cs:char list)
let q = "\""
let qP = pstring q
let pSemicolon = pstring ";"
let manyNoDoubleQuote = many $ noneOf q
let enquoted = between qP qP manyNoDoubleQuote |>> str
let skip = skipStringCI
let pContentType = skip "content-type: "
>>. manyTill anyChar (attempt $ preturn () .>> pSemicolon)
|>> str
let pBoundary = skip " boundary=" >>. enquoted
let pSubtype = opt $ pSemicolon >>. skip " type=" >>. enquoted
let pContent = many anyChar |>> str // TODO: The content parser needs to recurse on the stream.
let pStream = pipe4 pContentType pBoundary pSubtype pContent
$ fun c b t s -> { contentType=c; boundary=b; subtype=t; content=s }
let result s = match runParserOnStream pStream () "" s ascii with
| Success (r,_,_) -> r
| Failure (e,_,_) -> failwith (sprintf "%A" e)
let r = result s
member p.ContentType = r.contentType
member p.Boundary = r.boundary
member p.ContentSubtype = r.subtype
member p.Content = r.content
POST の例の最初の行は次のとおりです。
content-type: Multipart/related; boundary="RN-Http-Body-Boundary"; type="multipart/related"
ファイル内の 1 行にまたがります。コンテンツのさらにサブパートには、content-type
複数行にわたる値が含まれているため、パーサーを再利用する場合は、パーサーを改良する必要があることはわかっています。
どういうわけか、ストリームの残りを適切な境界で分割し、投稿のコンテンツの複数の部分を返すことができるようpContent
に、(文字列?) の結果を呼び出す必要があります。pBoundary
ヘッダーとコンテンツ (明らかに文字列以外のものである必要があります) を含む投稿。私の頭がクラクラします。このコードはすでに複雑すぎて、1 行を解析できません。
洞察と知恵に感謝します!