diff --git a/.gitignore b/.gitignore index 95a48fb..811096d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -uploads \ No newline at end of file +uploads +activity.log \ No newline at end of file diff --git a/main.go b/main.go index bb1d81e..1c3d97b 100644 --- a/main.go +++ b/main.go @@ -14,8 +14,41 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { // Check is already done in main() Chibisafe_basepath := os.Getenv("CHIBISAFE_BASEPATH") + // Open or create a file for appending logs + log_file, err := os.OpenFile("activity.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.Fatal(err) + } + defer log_file.Close() + log.SetOutput(log_file) + if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + log.Printf("[%s] : Method not allowed", r.RemoteAddr) + return + } + + // Check for x-api-key header + API_Key := r.Header.Get("x-api-key") + if API_Key == "" { + http.Error(w, "X-api-key is empty!", http.StatusBadRequest) + log.Printf("[%s] : X-api-key is empty!", r.RemoteAddr) + return + } + + // Set a limit on the request body size + maxUploadSize := 10 * 1024 * 1024 // 10 MB + r.Body = http.MaxBytesReader(w, r.Body, int64(maxUploadSize)) + + // ParseMultipartForm parses a request body as multipart/form-data + err = r.ParseMultipartForm(int64(maxUploadSize)) + if err != nil { + if err.Error() == "http: request body too large" { + http.Error(w, "File too large.", http.StatusRequestEntityTooLarge) + log.Printf("[%s] : Request Body is too large!", r.RemoteAddr) + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -26,20 +59,14 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { file, fileHeader, err := r.FormFile("file") if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) - log.Panic(err) + log.Printf("[%s] : %s", r.RemoteAddr, err) return } defer file.Close() - API_Key := r.Header.Get("x-api-key") - if API_Key == "" { - http.Error(w, "X-api-key is empty!", http.StatusBadRequest) - log.Panicf("X-api-key is empty!") - return - } - log.Printf("Received a successful POST from %s", r.RemoteAddr) + log.Printf("[%s] : Received a successful POST", r.RemoteAddr) tempfilepath := handler.GetTempFilename(fileHeader.Filename) - log.Printf("Successfully obtained temporary Filename : %s", tempfilepath) + log.Printf("[%s] [%s] : Successfully obtained temporary Filename", r.RemoteAddr, tempfilepath) handler.SaveFile(tempfilepath, file) handler.DiscardFile(file) @@ -49,21 +76,28 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { FileSize: fileHeader.Size, } - chibisafe_post, _ := handler.UploadPost(Chibisafe_basepath, PostData, API_Key) + chibisafe_post, err := handler.UploadPost(Chibisafe_basepath, PostData, API_Key) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + log.Printf("[%s] [%s] : %s", r.RemoteAddr, tempfilepath, err) + return + } + var chibisafe_Response_Metadata handler.UploadResponseMeta err = json.Unmarshal(chibisafe_post, &chibisafe_Response_Metadata) if err != nil { - log.Panic(err) + log.Print(err) return } - log.Printf("Successfully obtained PUT key with identifier: %s", chibisafe_Response_Metadata.Identifier) + log.Printf("[%s] [%s] [%s] : Successfully obtained PUT keys", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath) _, err = handler.NetworkStoragePut(chibisafe_Response_Metadata.URL, PostData.ContentType, tempfilepath) if err != nil { - log.Panic(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + log.Printf("[%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) return } - log.Printf("Successfully PUT file to Network Storage with identifier: %s", chibisafe_Response_Metadata.Identifier) + log.Printf("[%s] [%s] [%s] : Successfully PUT file to Network Storage", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath) PostProcessData := handler.UploadProcessMeta{ Name: fileHeader.Filename, @@ -71,23 +105,29 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { Identifier: chibisafe_Response_Metadata.Identifier, } - PostProcess, _ := handler.UploadProcessPost(Chibisafe_basepath, PostData.ContentType, chibisafe_Response_Metadata.Identifier, API_Key, PostProcessData) + PostProcess, err := handler.UploadProcessPost(Chibisafe_basepath, PostData.ContentType, chibisafe_Response_Metadata.Identifier, API_Key, PostProcessData) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + log.Printf("[%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) + return + } + var PostProcessResponse handler.UploadProcessResponseMeta err = json.Unmarshal(PostProcess, &PostProcessResponse) if err != nil { - log.Panic(err) + log.Print(err) return } - log.Printf("Successfully Processed Response with identifier: %s and UUID: %s", PostProcessResponse.Name, PostProcessResponse.UUID) + log.Printf("[%s] [%s] [%s] : Successfully Processed Response with UUID: %s", r.RemoteAddr, PostProcessResponse.Name, tempfilepath, PostProcessResponse.UUID) err = handler.DeleteFile(tempfilepath) if err != nil { - log.Panic(err) + log.Printf("[%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) return } - log.Printf("Successfully Deleted Temporary file from local disk Filename: %s", tempfilepath) - - fmt.Fprintf(w, "%s", PostProcessResponse.URL) + log.Printf("[%s] [%s] : Successfully Deleted Temporary file from local disk", r.RemoteAddr, tempfilepath) + JsonResponse, _ := json.Marshal(PostProcessResponse) + fmt.Fprintf(w, "%s", JsonResponse) } func main() { diff --git a/src/handler/chibisafe.go b/src/handler/chibisafe.go index f54e513..b205302 100644 --- a/src/handler/chibisafe.go +++ b/src/handler/chibisafe.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io" - "log" "net/http" "os" ) @@ -14,25 +13,23 @@ func UploadPost(BasePath string, PostData UploadPostMeta, accessKey string) ([]b // Convert PostData to JSON PostDataJson, err := json.Marshal(PostData) if err != nil { - log.Panic(err) return nil, err } - // Create a new request with POST method and request body - req, err := http.NewRequest(http.MethodPost, URL, bytes.NewBuffer(PostDataJson)) - if err != nil { - log.Panic(err) - return nil, err + headers := map[string]string{ + "X-Api-Key": accessKey, + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-API-Key", accessKey) + POSTStruct := URLRequest{ + URL: URL, + ContentType: PostData.ContentType, + Method: "POST", + Header: headers, + } - client := &http.Client{} - - resp, err := client.Do(req) + resp, err := HTTPBytes(POSTStruct, bytes.NewBuffer(PostDataJson)) if err != nil { - log.Panic(err) return nil, err } defer resp.Body.Close() @@ -40,13 +37,11 @@ func UploadPost(BasePath string, PostData UploadPostMeta, accessKey string) ([]b if resp.StatusCode == http.StatusOK { BodyRead, err := io.ReadAll(resp.Body) if err != nil { - log.Panic(err) return nil, err } return BodyRead, nil } else { - log.Panicf("Output from %s : %d", URL, resp.StatusCode) - return nil, nil + return nil, err } } @@ -56,33 +51,31 @@ func NetworkStoragePut(URL string, ContentType string, filepath string) ([]byte, // Open the file file, err := os.Open(filepath) if err != nil { - log.Panic(err) return nil, err } defer file.Close() - // Create an HTTP client - client := &http.Client{} - - // Create a PUT request with the file contents - req, err := http.NewRequest(http.MethodPut, URL, file) - if err != nil { - log.Panic(err) - return nil, err - } - defer req.Body.Close() - - // Set appropriate headers for the file - req.Header.Set("Content-Type", ContentType) - // Set ContentLenght filestat, _ := file.Stat() - req.ContentLength = filestat.Size() + + var filesize *int = new(int) + *filesize = int(filestat.Size()) + + headers := map[string]string{ + "Content-Type": ContentType, + } + + PUTStruct := URLRequest{ + URL: URL, + ContentType: ContentType, + Method: "PUT", + Header: headers, + ContentLength: filesize, + } // Send the request - resp, err := client.Do(req) + resp, err := HTTPOSFile(PUTStruct, file) if err != nil { - log.Panic(err) return nil, err } defer resp.Body.Close() @@ -90,12 +83,10 @@ func NetworkStoragePut(URL string, ContentType string, filepath string) ([]byte, if resp.StatusCode == http.StatusOK { BodyRead, err := io.ReadAll(resp.Body) if err != nil { - log.Panic(err) return nil, err } return BodyRead, nil } else { - log.Panicf("Output from %s : %d", URL, resp.StatusCode) return nil, err } } @@ -105,38 +96,33 @@ func UploadProcessPost(BasePath string, ContentType string, Identifier string, a // Convert PostData to JSON PostDataJson, err := json.Marshal(PostData) if err != nil { - log.Panic(err) return nil, err } - // Create a new request with POST method and request body - req, err := http.NewRequest("POST", URL, bytes.NewBuffer(PostDataJson)) + headers := map[string]string{ + "X-Api-Key": accessKey, + "Content-Type": "application/json", + } + + POSTStruct := URLRequest{ + URL: URL, + ContentType: ContentType, + Method: "POST", + Header: headers, + } + + resp, err := HTTPBytes(POSTStruct, bytes.NewBuffer(PostDataJson)) if err != nil { - log.Panic(err) return nil, err } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-API-Key", accessKey) - - client := &http.Client{} - - resp, err := client.Do(req) - if err != nil { - log.Panic(err) - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode == http.StatusOK { BodyRead, err := io.ReadAll(resp.Body) if err != nil { - log.Panic(err) return nil, err } return BodyRead, nil } else { - log.Panicf("Output from %s : %d", URL, resp.StatusCode) - return nil, nil + return nil, err } } diff --git a/src/handler/httpdo.go b/src/handler/httpdo.go new file mode 100644 index 0000000..04ad5d5 --- /dev/null +++ b/src/handler/httpdo.go @@ -0,0 +1,61 @@ +package handler + +import ( + "bytes" + "net/http" + "os" +) + +func HTTPBytes(RequestStruct URLRequest, RequestData *bytes.Buffer) (*http.Response, error) { + // Create a new request with POST method and request body + req, err := http.NewRequest(RequestStruct.Method, RequestStruct.URL, RequestData) + if err != nil { + return nil, err + } + + if RequestStruct.ContentLength != nil { + req.ContentLength = int64(*RequestStruct.ContentLength) + } + + for key, value := range RequestStruct.Header { + req.Header.Set(key, value) + } + + resp, err := HTTPClientDo(req) + if err != nil { + return nil, err + } + defer RequestData.Reset() + return resp, nil +} + +func HTTPOSFile(RequestStruct URLRequest, RequestData *os.File) (*http.Response, error) { + // Create a new request with POST method and request body + req, err := http.NewRequest(RequestStruct.Method, RequestStruct.URL, RequestData) + if err != nil { + return nil, err + } + + if RequestStruct.ContentLength != nil { + req.ContentLength = int64(*RequestStruct.ContentLength) + } + + for key, value := range RequestStruct.Header { + req.Header.Set(key, value) + } + + resp, err := HTTPClientDo(req) + if err != nil { + return nil, err + } + return resp, nil +} + +func HTTPClientDo(Request *http.Request) (*http.Response, error) { + client := &http.Client{} + response, err := client.Do(Request) + if err != nil { + return nil, err + } + return response, err +} diff --git a/src/handler/struct.go b/src/handler/struct.go index 8717ed8..826de80 100644 --- a/src/handler/struct.go +++ b/src/handler/struct.go @@ -23,3 +23,11 @@ type UploadProcessResponseMeta struct { UUID string `json:"uuid"` URL string `json:"url"` } + +type URLRequest struct { + URL string + ContentType string + Method string + ContentLength *int + Header map[string]string +}