--- name: upload_parse kind: function lang: go domain: infra version: "1.0.0" purity: impure signature: "func UploadParse(r *http.Request, maxSize int64) ([]ParsedFile, error)" description: "Parsea un request multipart/form-data y extrae todos los archivos adjuntos. Aplica http.MaxBytesReader para limitar el tamano. Carga el contenido en memoria como bytes.Reader." tags: [http, upload, multipart, parse, form, infra] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [bytes, fmt, io, mime/multipart, net/http, strings] params: - name: r desc: "http.Request con Content-Type multipart/form-data" - name: maxSize desc: "tamano maximo total del body en bytes (ej: 10<<20 para 10MB)" output: "slice de ParsedFile con FormField, Filename, Size, MIMEHint, Header (primeros 512 bytes para magic detection) y Content (io.Reader). Error si el body excede maxSize, content-type no es multipart o falla el parse" tested: true tests: ["extrae un archivo del multipart", "extrae multiples archivos", "rechaza content-type no multipart", "respeta maxSize"] test_file_path: "functions/infra/upload_parse_test.go" file_path: "functions/infra/upload_parse.go" --- ## Ejemplo ```go files, err := UploadParse(r, 10<<20) // 10 MB if err != nil { HTTPErrorResponse(w, HTTPError{Status: 400, Code: "parse_error", Message: err.Error()}) return } for _, f := range files { mime, ok := FileValidateType(f.Header, []string{"image/png", "image/jpeg"}) if !ok { continue } uploaded, _ := FileSaveDisk("./uploads", f.Filename, f.Content) log.Println(uploaded.Path, mime) } ``` ## Notas Esta implementacion carga TODO el contenido en memoria. Adecuada para archivos pequenos/medianos (<100MB). Para uploads enormes, usar `multipart.NewReader(r.Body, boundary)` directamente y stream-ear cada parte a disco/S3. `MIMEHint` viene del header del cliente y NO debe confiarse — usar `FileValidateType(f.Header, allowed)` para verificacion real.