-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
110 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,98 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"github.com/google/uuid" | ||
"io" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
) | ||
|
||
type Response struct { | ||
Origin string `json:"origin"` | ||
Method string `json:"method"` | ||
Url string `json:"url"` | ||
Args map[string][]string `json:"args"` | ||
Headers map[string][]string `json:"headers"` | ||
Body string `json:"body"` | ||
type Server struct { | ||
router *http.ServeMux | ||
} | ||
|
||
type echoHandler struct { | ||
debug bool | ||
} | ||
|
||
func (eh *echoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
u, _ := url.Parse(r.RequestURI) | ||
params, _ := url.ParseQuery(u.RawQuery) | ||
var body string | ||
if r.Body != nil { | ||
asBytes, _ := ioutil.ReadAll(r.Body) | ||
if asBytes != nil { | ||
body = string(asBytes) | ||
} | ||
} | ||
resp := Response{ | ||
Origin: r.RemoteAddr, | ||
Method: r.Method, | ||
Url: u.Path, | ||
Args: params, | ||
Headers: r.Header, | ||
Body: body, | ||
func main() { | ||
s := &Server{ | ||
router: http.NewServeMux(), | ||
} | ||
|
||
if eh.debug { | ||
log.Printf("Got %s on %s from %s:%s", r.Method, r.RequestURI, r.RemoteAddr, string(body)) | ||
} | ||
s.router.HandleFunc("POST /api/patient", s.createPatientHandler()) | ||
|
||
addr := "localhost:8080" | ||
|
||
fmt.Printf("Start listening at %s", addr) | ||
err := http.ListenAndServe(addr, s.router) | ||
|
||
// Encode json | ||
jsonResp, err := json.Marshal(resp) | ||
if err != nil { | ||
w.WriteHeader(http.StatusInternalServerError) | ||
return | ||
log.Fatal("could not start server") | ||
} | ||
} | ||
|
||
// write headers | ||
w.WriteHeader(http.StatusOK) | ||
w.Header().Set("Content-Type", "application/json") | ||
type CreatePatientRequest struct { | ||
Patient | ||
} | ||
|
||
// write formatted json body | ||
var formattedResp bytes.Buffer | ||
json.Indent(&formattedResp, jsonResp, "", "\t") | ||
w.Write(formattedResp.Bytes()) | ||
type CreatePatientResponse struct { | ||
UID string `json:"uid,omitempty"` | ||
Patient | ||
} | ||
|
||
type Patient struct { | ||
FullName string `json:"fullName,omitempty"` | ||
AddressLine string `json:"addressLine,omitempty"` | ||
Allergies []string `json:"allergies,omitempty"` | ||
} | ||
|
||
func main() { | ||
mux := http.NewServeMux() | ||
func (s *Server) createPatientHandler() http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
if r.Method != http.MethodPost { | ||
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) | ||
return | ||
} | ||
body, err := io.ReadAll(r.Body) | ||
|
||
if err != nil { | ||
http.Error(w, "Unable to read request body", http.StatusBadRequest) | ||
return | ||
} | ||
defer func(body io.ReadCloser) { | ||
err := body.Close() | ||
if err != nil { | ||
// log error | ||
} | ||
}(r.Body) | ||
|
||
cpr := CreatePatientRequest{} | ||
err = json.Unmarshal(body, &cpr) | ||
if err != nil { | ||
http.Error(w, "Unable to read request body", http.StatusBadRequest) | ||
return | ||
} | ||
|
||
patient := cpr.Patient | ||
patientID, err := s.CreatePatient(patient) | ||
|
||
resp := CreatePatientResponse{ | ||
UID: patientID, | ||
Patient: patient, | ||
} | ||
|
||
b, err := json.Marshal(resp) | ||
|
||
_, err = w.Write(b) | ||
|
||
if err != nil { | ||
http.Error(w, fmt.Sprintf("could not write response: %s", err), http.StatusInternalServerError) | ||
} | ||
} | ||
|
||
} | ||
|
||
h := &echoHandler{debug: true} | ||
mux.Handle("/", h) | ||
func (s *Server) CreatePatient(p Patient) (string, error) { | ||
uid := uuid.New().String() | ||
fmt.Printf("storing patient %+v, with uid %s", p, uid) | ||
Check failure Code scanning / CodeQL Log entries created from user input High
This log entry depends on a
user-provided value Error loading related location Loading |
||
|
||
fmt.Printf("Start listening at http://localhost:3000/\n") | ||
http.ListenAndServe(":3000", mux) | ||
return uid, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,50 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"github.com/stretchr/testify/assert" | ||
"io" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestServer(t *testing.T) { | ||
// mock response | ||
recorder := httptest.NewRecorder() | ||
ctx := context.Background() | ||
|
||
s := Server{router: http.NewServeMux()} | ||
|
||
cpr := CreatePatientRequest{Patient{ | ||
FullName: "Patrick", | ||
AddressLine: "a", | ||
Allergies: []string{"cilantro"}, | ||
}} | ||
|
||
b, err := json.Marshal(cpr) | ||
|
||
// create a http request that triggers your server | ||
req, _ := http.NewRequest("GET", "", nil) | ||
req.RemoteAddr = "1.2.3.4" | ||
req.RequestURI = "/doit?arg1=1&arg2=two" | ||
req.Header.Set("Accept", "application/json") | ||
assert.NoError(t, err) | ||
|
||
req, err := http.NewRequestWithContext(ctx, "POST", "/api/patient", bytes.NewBuffer(b)) | ||
assert.NoError(t, err) | ||
|
||
// call subject of test | ||
eh := echoHandler{true} | ||
eh.ServeHTTP(recorder, req) | ||
w := httptest.NewRecorder() | ||
|
||
// verify response | ||
assert.Equal(t, http.StatusOK, recorder.Code) | ||
s.createPatientHandler().ServeHTTP(w, req) | ||
|
||
// decode json | ||
dec := json.NewDecoder(recorder.Body) | ||
var resp Response | ||
err := dec.Decode(&resp) | ||
assert.Equal(t, http.StatusOK, w.Code) | ||
|
||
// json body | ||
resp := CreatePatientResponse{} | ||
body, err := io.ReadAll(w.Body) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "1.2.3.4", resp.Origin) | ||
assert.Equal(t, "/doit", resp.Url) | ||
assert.Equal(t, "1", resp.Args["arg1"][0]) | ||
assert.Equal(t, "two", resp.Args["arg2"][0]) | ||
assert.Equal(t, "application/json", resp.Headers["Accept"][0]) | ||
|
||
err = json.Unmarshal(body, &resp) | ||
assert.NoError(t, err) | ||
|
||
assert.Equal(t, "Patrick", resp.FullName) | ||
assert.Equal(t, "a", resp.AddressLine) | ||
assert.Len(t, resp.Allergies, 1) | ||
assert.Equal(t, "cilantro", resp.Allergies[0]) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters