@@ -116,7 +116,8 @@ func shortCmd(ctx context.Context, operate op, alias, link string) (err error) {
116116 return
117117}
118118
119- // sHandler redirects ...
119+ // sHandler redirects the current request to a known link if the alias
120+ // is found in the redir store.
120121func (s * server ) sHandler (w http.ResponseWriter , r * http.Request ) {
121122 ctx := r .Context ()
122123
@@ -131,35 +132,24 @@ func (s *server) sHandler(w http.ResponseWriter, r *http.Request) {
131132 }
132133 }()
133134
135+ // statistic page
134136 alias := strings .TrimSuffix (strings .TrimPrefix (r .URL .Path , conf .S .Prefix ), "/" )
135137 if alias == "" {
136138 err = s .stats (ctx , w )
137139 return
138140 }
139141
140- checkdb := func (url string ) (string , error ) {
141- raw , err := s .db .FetchAlias (ctx , alias )
142- if err != nil {
143- return "" , err
144- }
145- c := arecord {}
146- err = json .Unmarshal (StringToBytes (raw ), & c )
147- if err != nil {
148- return "" , err
149- }
150- if url != c .URL {
151- s .cache .Put (alias , c .URL )
152- url = c .URL
153- }
154- return url , nil
155- }
156-
142+ // figure out redirect location
157143 url , ok := s .cache .Get (alias )
158144 if ! ok {
159- url , err = checkdb (url )
145+ url , err = s . checkdb (ctx , alias )
160146 if err != nil {
161- return
147+ url , err = s .checkvcs (ctx , alias )
148+ if err != nil {
149+ return
150+ }
162151 }
152+ s .cache .Put (alias , url )
163153 }
164154
165155 // redirect the user immediate, but run pv/uv count in background
@@ -169,6 +159,58 @@ func (s *server) sHandler(w http.ResponseWriter, r *http.Request) {
169159 go func () { s .visitCh <- visit {s .readIP (r ), alias } }()
170160}
171161
162+ // checkdb checks whether the given alias is exsited in the redir database,
163+ // and updates the in-memory cache if
164+ func (s * server ) checkdb (ctx context.Context , alias string ) (string , error ) {
165+ raw , err := s .db .FetchAlias (ctx , alias )
166+ if err != nil {
167+ return "" , err
168+ }
169+ c := arecord {}
170+ err = json .Unmarshal (StringToBytes (raw ), & c )
171+ if err != nil {
172+ return "" , err
173+ }
174+ return c .URL , nil
175+ }
176+
177+ // checkvcs checks whether the given alias is an repository on VCS, if so,
178+ // then creates a new alias and returns url of the vcs repository.
179+ func (s * server ) checkvcs (ctx context.Context , alias string ) (string , error ) {
180+
181+ // construct the try path and make the request to vcs
182+ repoPath := conf .X .RepoPath
183+ if strings .HasSuffix (repoPath , "/*" ) {
184+ repoPath = strings .TrimSuffix (repoPath , "/*" )
185+ }
186+ tryPath := fmt .Sprintf ("%s/%s" , repoPath , alias )
187+ resp , err := http .Get (tryPath )
188+ if err != nil {
189+ return "" , err
190+ }
191+ defer resp .Body .Close ()
192+ if resp .StatusCode != http .StatusOK &&
193+ resp .StatusCode != http .StatusMovedPermanently {
194+ return "" , fmt .Errorf ("%s is not a repository" , tryPath )
195+ }
196+
197+ // figure out the new location
198+ if resp .StatusCode == http .StatusMovedPermanently {
199+ tryPath = resp .Header .Get ("Location" )
200+ }
201+
202+ // store such a try path
203+ err = s .db .StoreAlias (ctx , alias , tryPath )
204+ if err != nil {
205+ if errors .Is (err , errExistedAlias ) {
206+ return s .checkdb (ctx , alias )
207+ }
208+ return "" , err
209+ }
210+
211+ return tryPath , nil
212+ }
213+
172214// readIP implements a best effort approach to return the real client IP,
173215// it parses X-Real-IP and X-Forwarded-For in order to work properly with
174216// reverse-proxies such us: nginx or haproxy. Use X-Forwarded-For before
0 commit comments