MCPcopy Index your code
hub / github.com/coder/coder / postChatFile

Method postChatFile

coderd/exp_chats.go:6023–6149  ·  view source on GitHub ↗

EXPERIMENTAL: this endpoint is experimental and is subject to change. @Summary Upload chat file @ID upload-chat-file @Security CoderSessionToken @Tags Chats @Accept image/png,image/jpeg,image/gif,image/webp,text/plain,text/markdown,text/csv,application/json,application/pdf @Produce json @Param orga

(rw http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

6021// @Router /api/experimental/chats/files [post]
6022// @Description Experimental: this endpoint is subject to change.
6023func (api *API) postChatFile(rw http.ResponseWriter, r *http.Request) {
6024 ctx := r.Context()
6025 apiKey := httpmw.APIKey(r)
6026
6027 orgIDStr := r.URL.Query().Get("organization")
6028 if orgIDStr == "" {
6029 httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
6030 Message: "Missing organization query parameter.",
6031 })
6032 return
6033 }
6034 orgID, err := uuid.Parse(orgIDStr)
6035 if err != nil {
6036 httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
6037 Message: "Invalid organization ID.",
6038 })
6039 return
6040 }
6041 // NOTE: This authorize check is intentionally placed after query
6042 // parameter parsing because we need orgID to scope the RBAC check
6043 // to the correct org.
6044 if !api.Authorize(r, policy.ActionCreate, rbac.ResourceChat.WithOwner(apiKey.UserID.String()).InOrg(orgID)) {
6045 httpapi.Forbidden(rw)
6046 return
6047 }
6048
6049 contentType := r.Header.Get("Content-Type")
6050 if contentType == "" {
6051 contentType = "application/octet-stream"
6052 }
6053 // Strip parameters (e.g. "image/png; charset=utf-8" → "image/png")
6054 // so the allowlist check matches the base media type.
6055 if mediaType, _, err := mime.ParseMediaType(contentType); err == nil {
6056 contentType = mediaType
6057 }
6058 // application/octet-stream means the client could not classify the file
6059 // ahead of time, so we defer to byte classification below.
6060 if contentType != "application/octet-stream" && !chatfiles.IsAllowedStoredMediaType(contentType) {
6061 httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
6062 Message: "Unsupported file type.",
6063 Detail: fmt.Sprintf("Allowed types: %s.", chatfiles.AllowedStoredMediaTypesString()),
6064 })
6065 return
6066 }
6067
6068 // Extract filename from Content-Disposition header if provided.
6069 var filename string
6070 if cd := r.Header.Get("Content-Disposition"); cd != "" {
6071 if _, params, err := mime.ParseMediaType(cd); err == nil {
6072 filename = params["filename"]
6073 }
6074 }
6075
6076 r.Body = http.MaxBytesReader(rw, r.Body, codersdk.MaxChatFileSizeBytes)
6077 data, err := io.ReadAll(r.Body)
6078 if err != nil {
6079 var maxBytesErr *http.MaxBytesError
6080 if errors.As(err, &maxBytesErr) {

Callers

nothing calls this directly

Calls 15

AuthorizeMethod · 0.95
APIKeyFunction · 0.92
WriteFunction · 0.92
ForbiddenFunction · 0.92
IsAllowedStoredMediaTypeFunction · 0.92
PrepareStoredFileFunction · 0.92
InOrgMethod · 0.80
WithOwnerMethod · 0.80
AsMethod · 0.80
ContextMethod · 0.65

Tested by

no test coverage detected