Skip to content

Commit 71b665f

Browse files
youenadrienaury
andauthored
feat(http): add cors flags (#372)
* feat(http): add cors flags * docs(http): readme and changelog * docs(readme): remove duplicate `cors configuration` section * test(http): add venom test for cors headers * test(http): pull with cors header --------- Co-authored-by: Adrien Aury <44274230+adrienaury@users.noreply.github.com>
1 parent 3d7a1b1 commit 71b665f

File tree

7 files changed

+126
-7
lines changed

7 files changed

+126
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ Types of changes
1414
- `Fixed` for any bug fixes.
1515
- `Security` in case of vulnerabilities.
1616

17+
## [3.3.0]
18+
19+
- `Added` configurable CORS support to http command
20+
1721
## [3.2.1]
1822

1923
- `Fixed`Filter Parameter Not Working in "lino http" Command [#369](https://github.com/CGI-FR/LINO/issues/369)

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,49 @@ $ lino pull source --limit 3 | jq '{ "manager": .customer_store_id_fkey.store_ma
568568
}
569569
```
570570

571+
## HTTP Sub-Command
572+
573+
The `http` sub-command in LINO is used to start an HTTP server that facilitates the interaction with LINO's data management functionalities via HTTP requests. This allows users to pull and push data using common HTTP methods like `GET`, `POST`, and `PATCH`.
574+
575+
To start the server, you can use the command:
576+
577+
```bash
578+
lino http --port 8080
579+
```
580+
581+
Where `--port` specifies the port on which the server will listen. The default port is `8000` if not specified.
582+
583+
### Example of using the HTTP server:
584+
585+
Start the Server:
586+
587+
```bash
588+
lino http --port 8080
589+
```
590+
591+
Make an HTTP GET Request to Pull Data:
592+
593+
You can use curl or any other HTTP client to interact with the server. For instance, to pull data from the source, you would use:
594+
595+
```bash
596+
curl http://localhost:8080/api/v1/data/source
597+
```
598+
599+
This command retrieves data from the specified source via the LINO HTTP interface.
600+
601+
Others HTTP methods are available in the tests [here](tests/suites/http/pull.yml)
602+
603+
### CORS Configuration
604+
605+
The HTTP server also supports Cross-Origin Resource Sharing (CORS), which is essential for managing resource access from different origins. You can enable and configure CORS to fit your needs:
606+
- `--cors-headers strings`: Allowed CORS headers (default `[Content-Type,Authorization]`)
607+
- `--cors-methods strings`: Allowed CORS methods (default `[GET,POST,OPTIONS,DELETE]`)
608+
- `--cors-origins strings`: Allowed CORS origins (e.g. `http://localhost:3000`) (default `[*]`)
609+
- `--enable-cors`: Enable CORS support
610+
611+
These flags allow you to specify which headers, methods, and origins are allowed, providing flexible control over your server's security and accessibility.
612+
613+
571614
## Installation
572615

573616
Download the last binary release in your path.

docker-compose.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,13 @@ services:
8989
environment:
9090
- PASSWORD=sakila
9191
- CGO_ENABLED=0
92-
command: http
92+
command:
93+
- http
94+
- --enable-cors
95+
- --cors-origins
96+
- http://localhost:3000
97+
- --cors-methods
98+
- GET
9399
expose:
94100
- 8000
95101
volumes:

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ require (
1919
github.com/mattn/go-isatty v0.0.20
2020
github.com/microsoft/go-mssqldb v1.8.0
2121
github.com/mitchellh/go-homedir v1.1.0
22+
github.com/rs/cors v1.11.1
2223
github.com/rs/zerolog v1.33.0
2324
github.com/schollz/progressbar/v3 v3.18.0
2425
github.com/sijms/go-ora/v2 v2.8.24

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
338338
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
339339
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
340340
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
341+
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
342+
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
341343
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
342344
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
343345
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=

internal/app/http/cli.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,23 @@ import (
2222
"net/http"
2323
"os"
2424

25-
"github.com/gorilla/mux"
26-
"github.com/spf13/cobra"
27-
2825
"github.com/cgi-fr/lino/internal/app/pull"
2926
"github.com/cgi-fr/lino/internal/app/push"
27+
28+
"github.com/gorilla/mux"
29+
"github.com/rs/cors"
30+
"github.com/spf13/cobra"
3031
)
3132

3233
// NewCommand implements the cli http command
3334
func NewCommand(fullName string, err *os.File, out *os.File, in *os.File) *cobra.Command {
3435
var (
3536
port uint
3637
ingressDescriptor string
38+
enableCORS bool
39+
corsOrigins []string
40+
corsMethods []string
41+
corsHeaders []string
3742
)
3843

3944
cmd := &cobra.Command{
@@ -43,9 +48,9 @@ func NewCommand(fullName string, err *os.File, out *os.File, in *os.File) *cobra
4348
Example: fmt.Sprintf(" %[1]s http --port 8080", fullName),
4449
Args: cobra.ExactArgs(0),
4550
Run: func(cmd *cobra.Command, args []string) {
46-
r := mux.NewRouter()
51+
router := mux.NewRouter()
4752

48-
api := r.PathPrefix("/api/v1").Subrouter()
53+
api := router.PathPrefix("/api/v1").Subrouter()
4954

5055
api.Path("/data/{dataSource}").
5156
Methods(http.MethodGet).
@@ -67,8 +72,23 @@ func NewCommand(fullName string, err *os.File, out *os.File, in *os.File) *cobra
6772
Methods(http.MethodPost).
6873
HandlerFunc(push.TruncatHandlerFactory(ingressDescriptor))
6974

70-
http.Handle("/", r)
75+
var handler http.Handler = router
76+
77+
if enableCORS {
78+
fmt.Printf("enable cors :%s\n", corsOrigins)
79+
80+
corsHandler := cors.New(cors.Options{
81+
AllowedOrigins: corsOrigins,
82+
AllowedMethods: corsMethods,
83+
AllowedHeaders: corsHeaders,
84+
})
85+
handler = corsHandler.Handler(router)
86+
}
87+
88+
http.Handle("/", handler)
7189
bind := fmt.Sprintf(":%d", port)
90+
fmt.Printf("listen on :%d\n", port)
91+
7292
e1 := http.ListenAndServe(bind, nil) //nolint:gosec
7393

7494
if err != nil {
@@ -79,6 +99,13 @@ func NewCommand(fullName string, err *os.File, out *os.File, in *os.File) *cobra
7999
}
80100
cmd.Flags().UintVarP(&port, "port", "p", 8000, "HTTP Port to bind")
81101
cmd.Flags().StringVarP(&ingressDescriptor, "ingress-descriptor", "i", "ingress-descriptor.yaml", "Ingress descriptor filename")
102+
103+
// CORS flags
104+
cmd.Flags().BoolVar(&enableCORS, "enable-cors", false, "Enable CORS support")
105+
cmd.Flags().StringSliceVar(&corsOrigins, "cors-origins", []string{"*"}, "Allowed CORS origins (e.g. http://localhost:3000)")
106+
cmd.Flags().StringSliceVar(&corsMethods, "cors-methods", []string{"GET", "POST", "OPTIONS", "DELETE"}, "Allowed CORS methods")
107+
cmd.Flags().StringSliceVar(&corsHeaders, "cors-headers", []string{"Content-Type", "Authorization"}, "Allowed CORS headers")
108+
82109
cmd.SetOut(out)
83110
cmd.SetErr(err)
84111
cmd.SetIn(in)

tests/suites/http/pull.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,39 @@ testcases:
118118
assertions:
119119
- result.statuscode ShouldEqual 200
120120
- result.bodyjson.address_id ShouldEqual 15
121+
122+
- name: pull whith good Origin header
123+
steps:
124+
- type: http
125+
method: GET
126+
url: http://lino:8000/api/v1/data/source?limit=1
127+
headers:
128+
Origin: http://localhost:3000
129+
130+
assertions:
131+
- result.statuscode ShouldEqual 200
132+
- result.headers.Access-Control-Allow-Origin ShouldEqual http://localhost:3000
133+
134+
- name: pull with bad Origin header
135+
steps:
136+
- type: http
137+
method: GET
138+
url: http://lino:8000/api/v1/data/source?limit=1
139+
headers:
140+
Origin: http://foo.com
141+
142+
assertions:
143+
- result.statuscode ShouldEqual 200
144+
- result.headers.Access-Control-Allow-Origin ShouldBeNil
145+
146+
- name: pull with bad method
147+
steps:
148+
- type: http
149+
method: POST
150+
url: http://lino:8000/api/v1/
151+
headers:
152+
Origin: http://localhost:3000
153+
154+
assertions:
155+
- result.statuscode ShouldEqual 404
156+
- result.headers.Access-Control-Allow-Origin ShouldBeNil

0 commit comments

Comments
 (0)