File size: 4,878 Bytes
8a2d2c4
 
 
 
 
 
 
 
 
6bb6e48
 
 
8a2d2c4
 
 
 
6bb6e48
 
48f0d3f
6bb6e48
f8a991f
8a2d2c4
 
 
 
 
 
 
 
 
6bb6e48
 
 
42d6c6c
6bb6e48
 
8a2d2c4
f8a991f
 
 
 
 
8a2d2c4
6bb6e48
48f0d3f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6bb6e48
48f0d3f
6bb6e48
8a2d2c4
 
 
 
 
 
 
 
6bb6e48
42d6c6c
6bb6e48
 
42d6c6c
 
6bb6e48
 
8a2d2c4
f8a991f
 
 
 
 
 
6bb6e48
 
48f0d3f
6bb6e48
f8a991f
 
 
 
 
 
 
 
 
6bb6e48
 
 
42d6c6c
6bb6e48
 
f8a991f
 
 
 
 
 
8a2d2c4
6bb6e48
 
 
 
8a2d2c4
 
 
 
6bb6e48
8a2d2c4
 
f8a991f
8a2d2c4
6bb6e48
 
 
 
8a2d2c4
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import argparse
import requests
from flask import Flask, request, Response, send_from_directory

app = Flask(__name__, static_folder="static", template_folder="templates")

EDITOR_BASE = "http://localhost:5555"
API_BASE = "http://localhost:5556"

# ---------------------------------------------------------
# 1. Combined UI page
# ---------------------------------------------------------
@app.route("/")
def index():
    return send_from_directory("templates", "index.html")


# ---------------------------------------------------------
# 2. Reverse proxy to ConlluEditor (UI + static)
# ---------------------------------------------------------
@app.route("/editor/", defaults={"path": ""}, methods=["GET", "POST"])
@app.route("/editor/<path:path>", methods=["GET", "POST"])
def proxy_editor(path):
    url = f"{EDITOR_BASE}/{path}"
    if request.query_string:
        url += "?" + request.query_string.decode()

    if request.method == "GET":
        r = requests.get(url, headers=_filtered_headers(), stream=True)
    else:
        r = requests.post(
            url,
            data=request.get_data(),
            headers={"Content-Type": request.headers.get("Content-Type")},
            stream=True
        )

    return Response(
        r.iter_content(chunk_size=8192),
        status=r.status_code,
        headers=_proxied_response_headers(r)
    )


# Handle /editor (no slash)
@app.route("/editor", methods=["GET", "POST"])
def proxy_editor_noslash():
    return proxy_editor("")


# ---------------------------------------------------------
# 3. Reverse proxy for ConlluEditor internal API (/edit/*)
# ---------------------------------------------------------
@app.route("/edit/<path:path>", methods=["GET", "POST"])
def proxy_editor_api(path):
    url = f"{EDITOR_BASE}/edit/{path}"
    if request.query_string:
        url += "?" + request.query_string.decode()

    if request.method == "GET":
        r = requests.get(url, headers=_filtered_headers(), stream=True)
    else:
        r = requests.post(
            url,
            data=request.get_data(),
            headers={"Content-Type": request.headers.get("Content-Type")},
            stream=True
        )

    return Response(
        r.iter_content(chunk_size=8192),
        status=r.status_code,
        headers=_proxied_response_headers(r)
    )


# ---------------------------------------------------------
# 4. Reverse proxy to Upload API (/api/*)
# ---------------------------------------------------------
@app.route("/api/<path:path>", methods=["GET", "POST"])
def proxy_api(path):
    url = f"{API_BASE}/api/{path}"
    if request.query_string:
        url += "?" + request.query_string.decode()

    if request.method == "GET":
        r = requests.get(url, headers=_filtered_headers(), stream=True)
    else:
        # Forward raw body + content-type so Flask can parse multipart uploads
        r = requests.post(
            url,
            data=request.get_data(),
            headers={"Content-Type": request.headers.get("Content-Type")},
            stream=True
        )

    return Response(
        r.iter_content(chunk_size=8192),
        status=r.status_code,
        headers=_proxied_response_headers(r)
    )


# ---------------------------------------------------------
# 5. Catch‑all: static assets for ConlluEditor
# ---------------------------------------------------------
@app.route("/<path:path>", methods=["GET", "POST"])
def proxy_static(path):
    url = f"{EDITOR_BASE}/{path}"
    if request.query_string:
        url += "?" + request.query_string.decode()

    if request.method == "GET":
        r = requests.get(url, headers=_filtered_headers(), stream=True)
    else:
        r = requests.post(
            url,
            data=request.get_data(),
            headers={"Content-Type": request.headers.get("Content-Type")},
            stream=True
        )

    return Response(
        r.iter_content(chunk_size=8192),
        status=r.status_code,
        headers=_proxied_response_headers(r)
    )


# ---------------------------------------------------------
# Header filtering helpers
# ---------------------------------------------------------
def _filtered_headers():
    excluded = {"host", "content-length", "content-encoding", "connection"}
    return {k: v for k, v in request.headers.items() if k.lower() not in excluded}


def _proxied_response_headers(r):
    excluded = {"content-encoding", "transfer-encoding", "connection"}
    return [(k, v) for k, v in r.headers.items() if k.lower() not in excluded]


# ---------------------------------------------------------
# Main entry
# ---------------------------------------------------------
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--port", type=int, default=7860)
    args = parser.parse_args()
    app.run(host="0.0.0.0", port=args.port)