@@ -57,7 +57,7 @@ func (pypiEcosystem) parsePackage(path string) (string, string) {
5757 path = strings .TrimPrefix (path , "/" )
5858 if after , ok := strings .CutPrefix (path , "simple/" ); ok {
5959 return strings .TrimSuffix (after , "/" ), ""
60- } else if strings .HasPrefix (path , "/ packages/" ) {
60+ } else if strings .HasPrefix (path , "packages/" ) {
6161 filename := filepath .Base (path )
6262 matches := pypiFilenameRe .FindStringSubmatch (filename )
6363 if len (matches ) > 2 {
@@ -106,9 +106,7 @@ func (pypiEcosystem) writeResponse(c shared.Context, data []byte, path string, c
106106
107107// ProxyPyPIPackage handles explicit-version PyPI package downloads (from /packages/).
108108// Route: GET /pypi/packages/*
109- func (d * DependencyProxyController ) ProxyPyPIPackage (c shared.Context ) error {
110- pypi := pypiEcosystem {}
111-
109+ func (d * PythonDependencyProxyController ) ProxyPyPIPackage (c shared.Context ) error {
112110 configs , err := d .GetDependencyProxyConfigs (c )
113111 if err != nil {
114112 slog .Error ("Error getting dependency proxy configs" , "error" , err )
@@ -127,8 +125,8 @@ func (d *DependencyProxyController) ProxyPyPIPackage(c shared.Context) error {
127125 defer span .End ()
128126 c .SetRequest (c .Request ().WithContext (ctx ))
129127
130- if c . Request (). Method != http . MethodGet && c . Request (). Method != http . MethodHead {
131- return echo . NewHTTPError ( http . StatusMethodNotAllowed , "Method not allowed" )
128+ if err := ensureReadMethod ( c ); err != nil {
129+ return err
132130 }
133131
134132 slog .Info ("Proxy request" , "proxy" , "pypi" , "type" , "package" , "method" , c .Request ().Method , "path" , requestPath )
@@ -191,12 +189,7 @@ func (d *DependencyProxyController) ProxyPyPIPackage(c shared.Context) error {
191189
192190 if statusCode != http .StatusOK {
193191 slog .Debug ("Upstream returned non-OK status" , "proxy" , "pypi" , "status" , statusCode )
194- for key , values := range headers {
195- for _ , value := range values {
196- c .Response ().Header ().Add (key , value )
197- }
198- }
199- return c .Blob (statusCode , headers .Get ("Content-Type" ), data )
192+ return d .passthroughUpstreamResponse (c , headers , statusCode , data )
200193 }
201194
202195 if err := d .CacheDataWithIntegrity (cachePath , data ); err != nil {
@@ -212,9 +205,7 @@ func (d *DependencyProxyController) ProxyPyPIPackage(c shared.Context) error {
212205
213206// ProxyPyPISimple handles PyPI /simple/ metadata requests, resolving the latest version before checking rules.
214207// Route: GET /pypi/simple/:package
215- func (d * DependencyProxyController ) ProxyPyPISimple (c shared.Context ) error {
216- pypi := pypiEcosystem {}
217-
208+ func (d * PythonDependencyProxyController ) ProxyPyPISimple (c shared.Context ) error {
218209 configs , err := d .GetDependencyProxyConfigs (c )
219210 if err != nil {
220211 slog .Error ("Error getting dependency proxy configs" , "error" , err )
@@ -234,8 +225,8 @@ func (d *DependencyProxyController) ProxyPyPISimple(c shared.Context) error {
234225 defer span .End ()
235226 c .SetRequest (c .Request ().WithContext (ctx ))
236227
237- if c . Request (). Method != http . MethodGet && c . Request (). Method != http . MethodHead {
238- return echo . NewHTTPError ( http . StatusMethodNotAllowed , "Method not allowed" )
228+ if err := ensureReadMethod ( c ); err != nil {
229+ return err
239230 }
240231
241232 slog .Info ("Proxy request" , "proxy" , "pypi" , "type" , "simple" , "method" , c .Request ().Method , "path" , requestPath )
@@ -254,12 +245,7 @@ func (d *DependencyProxyController) ProxyPyPISimple(c shared.Context) error {
254245
255246 if statusCode != http .StatusOK {
256247 slog .Debug ("Upstream returned non-OK status" , "proxy" , "pypi" , "status" , statusCode )
257- for key , values := range headers {
258- for _ , value := range values {
259- c .Response ().Header ().Add (key , value )
260- }
261- }
262- return c .Blob (statusCode , headers .Get ("Content-Type" ), data )
248+ return d .passthroughUpstreamResponse (c , headers , statusCode , data )
263249 }
264250
265251 // Fetch the PyPI JSON API to resolve version and release time before checking rules —
@@ -315,7 +301,7 @@ func (d *DependencyProxyController) ProxyPyPISimple(c shared.Context) error {
315301 return pypi .writeResponse (c , data , requestPath , false )
316302}
317303
318- func (d * DependencyProxyController ) fetchPyPIFromUpstream (ctx context.Context , requestPath string , headers http.Header ) ([]byte , http.Header , int , error ) {
304+ func (d * PythonDependencyProxyController ) fetchPyPIFromUpstream (ctx context.Context , requestPath string , headers http.Header ) ([]byte , http.Header , int , error ) {
319305 requestPath = strings .TrimRight (requestPath , "/" )
320306 url , err := url .JoinPath (pypiRegistry , requestPath )
321307 if err != nil {
@@ -351,7 +337,7 @@ func (d *DependencyProxyController) fetchPyPIFromUpstream(ctx context.Context, r
351337
352338// ExtractPyPIReleaseTime parses a PyPI JSON API response and returns the resolved version and its upload time.
353339// If version is empty, it uses info.version (the current release).
354- func (d * DependencyProxyController ) ExtractPyPIReleaseTime (data []byte , version string ) (string , time.Time , bool ) {
340+ func (d * PythonDependencyProxyController ) ExtractPyPIReleaseTime (data []byte , version string ) (string , time.Time , bool ) {
355341 var metadata struct {
356342 Info struct {
357343 Version string `json:"version"`
@@ -378,7 +364,7 @@ func (d *DependencyProxyController) ExtractPyPIReleaseTime(data []byte, version
378364}
379365
380366// fetchPyPILatestVersionAndReleaseTime fetches the PyPI JSON API and returns the resolved version and its release time.
381- func (d * DependencyProxyController ) fetchPyPILatestVersionAndReleaseTime (ctx context.Context , pkgName string ) (string , time.Time , bool ) {
367+ func (d * PythonDependencyProxyController ) fetchPyPILatestVersionAndReleaseTime (ctx context.Context , pkgName string ) (string , time.Time , bool ) {
382368 data , _ , statusCode , err := d .fetchPyPIFromUpstream (ctx , "/pypi/" + pkgName + "/json" , http.Header {})
383369 if err != nil || statusCode != http .StatusOK {
384370 return "" , time.Time {}, false
0 commit comments