diff options
| author | Antonin Bourguignon <abo@openerp.com> | 2012-08-06 19:08:41 +0200 |
|---|---|---|
| committer | Antonin Bourguignon <abo@openerp.com> | 2012-08-06 19:08:41 +0200 |
| commit | a52eeef5194b5fdab2b1d659f383c7589a2ebb98 (patch) | |
| tree | b494ed4d9c36efccba46a2814bea097af47b57f7 /addons/document_webdav | |
| parent | d928b07ace2b1f9b8a50ef11075cbea0fa9a6060 (diff) | |
[IMP] rephrase some error and warning messages in document, edi, google_base_account, mrp and mrp_repair
remove exclamation marks at the end of messages
remove unjustified capital letters
bzr revid: abo@openerp.com-20120806170841-cx9vuend1vglmsqk
Diffstat (limited to 'addons/document_webdav')
| -rw-r--r-- | addons/document_webdav/dav_fs.py | 76 | ||||
| -rw-r--r-- | addons/document_webdav/document_webdav.py | 26 | ||||
| -rwxr-xr-x | addons/document_webdav/test_davclient.py | 76 | ||||
| -rw-r--r-- | addons/document_webdav/webdav_server.py | 26 |
4 files changed, 102 insertions, 102 deletions
diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 13edfd8f77f..54a960efeff 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -78,13 +78,13 @@ def _str2time(cre): class BoundStream2(object): """Wraps around a seekable buffer, reads a determined range of data - + Note that the supplied stream object MUST support a size() which should return its data length (in bytes). - + A variation of the class in websrv_lib.py """ - + def __init__(self, stream, offset=None, length=None, chunk_size=None): self._stream = stream self._offset = offset or 0 @@ -99,7 +99,7 @@ class BoundStream2(object): def read(self, size=-1): if not self._stream: raise IOError(errno.EBADF, "read() without stream.") - + if self._rem_length == 0: return '' elif self._rem_length < 0: @@ -110,7 +110,7 @@ class BoundStream2(object): rsize = size if self._chunk_size and self._chunk_size < rsize: rsize = self._chunk_size - + data = self._stream.read(rsize) self._rem_length -= len(data) @@ -136,25 +136,25 @@ class BoundStream2(object): """ if whence == os.SEEK_SET: if pos < 0 or pos > self._length: - raise IOError(errno.EINVAL,"Cannot seek!") + raise IOError(errno.EINVAL,"Cannot seek.") self._stream.seek(pos - self._offset) self._rem_length = self._length - pos elif whence == os.SEEK_CUR: if pos > 0: if pos > self._rem_length: - raise IOError(errno.EINVAL,"Cannot seek past end!") + raise IOError(errno.EINVAL,"Cannot seek past end.") elif pos < 0: oldpos = self.tell() if oldpos + pos < 0: - raise IOError(errno.EINVAL,"Cannot seek before start!") + raise IOError(errno.EINVAL,"Cannot seek before start.") self._stream.seek(pos, os.SEEK_CUR) self._rem_length -= pos elif whence == os.SEEK_END: if pos > 0: - raise IOError(errno.EINVAL,"Cannot seek past end!") + raise IOError(errno.EINVAL,"Cannot seek past end.") else: if self._length + pos < 0: - raise IOError(errno.EINVAL,"Cannot seek before start!") + raise IOError(errno.EINVAL,"Cannot seek before start.") newpos = self._offset + self._length + pos self._stream.seek(newpos, os.SEEK_SET) self._rem_length = 0 - pos @@ -400,7 +400,7 @@ class openerp_dav_handler(dav_interface): domain = None if filters: domain = node.get_domain(cr, filters) - + if hasattr(filters, 'getElementsByTagNameNS'): hrefs = filters.getElementsByTagNameNS('DAV:', 'href') if hrefs: @@ -434,7 +434,7 @@ class openerp_dav_handler(dav_interface): except DAV_Error: raise except Exception, e: - self.parent.log_error("Cannot get_children: "+ str(e)) + self.parent.log_error("Cannot get_children: "+str(e)+".") raise finally: if cr: cr.close() @@ -488,7 +488,7 @@ class openerp_dav_handler(dav_interface): if not node: raise DAV_NotFound2(uri2) # TODO: if node is a collection, for some specific set of - # clients ( web browsers; available in node context), + # clients ( web browsers; available in node context), # we may return a pseydo-html page with the directory listing. try: res = node.open_data(cr,'r') @@ -508,7 +508,7 @@ class openerp_dav_handler(dav_interface): else: length = res.size() - start res = BoundStream2(res, offset=start, length=length) - + except TypeError,e: # for the collections that return this error, the DAV standard # says we'd better just return 200 OK with empty data @@ -564,10 +564,10 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def _get_dav_getcontentlength(self, uri): - """ return the content length of an object """ + """ return the content length of an object """ self.parent.log_message('get length: %s' % uri) result = 0 - cr, uid, pool, dbname, uri2 = self.get_cr(uri) + cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() return str(result) @@ -602,7 +602,7 @@ class openerp_dav_handler(dav_interface): cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: return time.time() - try: + try: node = self.uri2object(cr, uid, pool, uri2) if not node: raise DAV_NotFound2(uri2) @@ -623,11 +623,11 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def get_creationdate(self, uri): - """ return the last modified date of the object """ + """ return the last modified date of the object """ cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: raise DAV_Error, 409 - try: + try: node = self.uri2object(cr, uid, pool, uri2) if not node: raise DAV_NotFound2(uri2) @@ -643,7 +643,7 @@ class openerp_dav_handler(dav_interface): if not dbname: if cr: cr.close() return 'httpd/unix-directory' - try: + try: node = self.uri2object(cr, uid, pool, uri2) if not node: raise DAV_NotFound2(uri2) @@ -651,8 +651,8 @@ class openerp_dav_handler(dav_interface): return result #raise DAV_NotFound, 'Could not find %s' % path finally: - if cr: cr.close() - + if cr: cr.close() + def mkcol(self,uri): """ create a new collection see par. 9.3 of rfc4918 @@ -690,9 +690,9 @@ class openerp_dav_handler(dav_interface): node = self.uri2object(cr, uid, pool, uri2[:]) except Exception: node = False - + objname = misc.ustr(uri2[-1]) - + ret = None if not node: dir_node = self.uri2object(cr, uid, pool, uri2[:-1]) @@ -706,14 +706,14 @@ class openerp_dav_handler(dav_interface): cr.commit() cr.close() raise DAV_Error(400, "Failed to create resource.") - + uparts=urlparse.urlparse(uri) fileloc = '/'.join(newchild.full_path()) if isinstance(fileloc, unicode): fileloc = fileloc.encode('utf-8') # the uri we get is a mangled one, where the davpath has been removed davpath = self.parent.get_davpath() - + surl = '%s://%s' % (uparts[0], uparts[1]) uloc = urllib.quote(fileloc) hurl = False @@ -727,19 +727,19 @@ class openerp_dav_handler(dav_interface): ret = (str(hurl), etag) else: self._try_function(node.set_data, (cr, data), "save %s" % objname, cr=cr) - + cr.commit() cr.close() return ret def rmcol(self,uri): """ delete a collection """ - cr, uid, pool, dbname, uri2 = self.get_cr(uri) + cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() raise DAV_Error, 409 - node = self.uri2object(cr, uid, pool, uri2) + node = self.uri2object(cr, uid, pool, uri2) self._try_function(node.rmcol, (cr,), "rmcol %s" % uri, cr=cr) cr.commit() @@ -748,14 +748,14 @@ class openerp_dav_handler(dav_interface): def rm(self,uri): cr, uid, pool,dbname, uri2 = self.get_cr(uri) - if not dbname: + if not dbname: if cr: cr.close() raise DAV_Error, 409 node = self.uri2object(cr, uid, pool, uri2) res = self._try_function(node.rm, (cr,), "rm %s" % uri, cr=cr) if not res: if cr: cr.close() - raise OSError(1, 'Operation not permited.') + raise OSError(1, 'Operation not permitted.') cr.commit() cr.close() return 204 @@ -922,8 +922,8 @@ class openerp_dav_handler(dav_interface): return result def unlock(self, uri, token): - """ Unlock a resource from that token - + """ Unlock a resource from that token + @return True if unlocked, False if no lock existed, Exceptions """ cr, uid, pool, dbname, uri2 = self.get_cr(uri) @@ -959,9 +959,9 @@ class openerp_dav_handler(dav_interface): node = self.uri2object(cr, uid, pool, uri2[:]) except Exception: node = False - + objname = misc.ustr(uri2[-1]) - + if not node: dir_node = self.uri2object(cr, uid, pool, uri2[:-1]) if not dir_node: @@ -976,7 +976,7 @@ class openerp_dav_handler(dav_interface): cr.commit() cr.close() raise DAV_Error(400, "Failed to create resource.") - + created = True try: @@ -993,9 +993,9 @@ class openerp_dav_handler(dav_interface): cr.commit() cr.close() raise DAV_Error(423, "Resource already locked.") - + assert isinstance(lres, list), 'lres: %s' % repr(lres) - + try: data = mk_lock_response(self, uri, lres) cr.commit() diff --git a/addons/document_webdav/document_webdav.py b/addons/document_webdav/document_webdav.py index 4388c92b004..f53353dd43c 100644 --- a/addons/document_webdav/document_webdav.py +++ b/addons/document_webdav/document_webdav.py @@ -43,7 +43,7 @@ class document_davdir(osv.osv): elif dbro.type == 'ressource': return nodes.node_res_dir else: - raise ValueError("Directory node for %s type", dbro.type) + raise ValueError("Directory node for %s type.", dbro.type) def _prepare_context(self, cr, uid, nctx, context=None): nctx.node_file_class = nodes.node_file @@ -67,18 +67,18 @@ document_davdir() class dav_dir_property(osv.osv): """ Arbitrary WebDAV properties, attached to document.directories. - + Some DAV properties have to be settable at directories, depending on the database directory structure. - + Example would be the principal-URL. - + There _can_ be properties without a directory, which means that they globally apply to all the directories (aka. collections) of the present database. """ _name = 'document.webdav.dir.property' - + _columns = { 'create_date': fields.datetime('Date Created', readonly=True), 'create_uid': fields.many2one('res.users', 'Creator', readonly=True), @@ -90,25 +90,25 @@ class dav_dir_property(osv.osv): 'value': fields.text('Value'), 'do_subst': fields.boolean('Substitute', required=True), } - + _defaults = { 'do_subst': False, } - + dav_dir_property() class dav_file_property(osv.osv): """ Arbitrary WebDAV properties, attached to ir.attachments. - + A special case is the locks that can be applied on file nodes. - + There _can_ be properties without a file (RFC?), which means that they globally apply to all the attachments of the present database. - + TODO access permissions, per property. """ _name = 'document.webdav.file.property' - + _columns = { 'create_date': fields.datetime('Date Created', readonly=True), 'create_uid': fields.many2one('res.users', 'Creator', readonly=True), @@ -120,11 +120,11 @@ class dav_file_property(osv.osv): 'value': fields.text('Value'), 'do_subst': fields.boolean('Substitute', required=True), } - + _defaults = { 'do_subst': False, } - + dav_file_property() #eof diff --git a/addons/document_webdav/test_davclient.py b/addons/document_webdav/test_davclient.py index a0b498f61d0..f1f2e58c835 100755 --- a/addons/document_webdav/test_davclient.py +++ b/addons/document_webdav/test_davclient.py @@ -69,9 +69,9 @@ class PersistentTransport(Transport): host, extra_headers, x509 = Transport.get_host_info(self,host) if extra_headers == None: extra_headers = [] - + extra_headers.append( ( 'Connection', 'keep-alive' )) - + return host, extra_headers, x509 def _parse_response(self, file, sock, response): @@ -122,9 +122,9 @@ class PersistentTransport(Transport): resp = h._conn.getresponse() # TODO: except BadStatusLine, e: - + errcode, errmsg, headers = resp.status, resp.reason, resp.msg - + if errcode != 200: raise ProtocolError( @@ -145,7 +145,7 @@ class PersistentTransport(Transport): class CompressedTransport(PersistentTransport): def send_content(self, connection, request_body): connection.putheader("Content-Type", "text/xml") - + if len(request_body) > 512 or True: buffer = StringIO.StringIO() output = gzip.GzipFile(mode='wb', fileobj=buffer) @@ -176,7 +176,7 @@ class SafePersistentTransport(PersistentTransport): class AuthClient(object): def getAuth(self, atype, realm): raise NotImplementedError("Cannot authenticate for %s" % atype) - + def resolveFailedRealm(self, realm): """ Called when, using a known auth type, the realm is not in cache """ @@ -195,7 +195,7 @@ class BasicAuthClient(AuthClient): _logger.debug("missing key: \"%s\"" % realm) self.resolveFailedRealm(realm) return 'Basic '+ self._realm_dict[realm] - + def addLogin(self, realm, username, passwd): """ Add some known username/password for a specific login. This function should be called once, for each realm @@ -210,7 +210,7 @@ class BasicAuthClient(AuthClient): class addAuthTransport: """ Intermediate class that authentication algorithm to http transport """ - + def setAuthClient(self, authobj): """ Set the authentication client object. This method must be called before any request is issued, that @@ -218,7 +218,7 @@ class addAuthTransport: """ assert isinstance(authobj, AuthClient) self._auth_client = authobj - + def request(self, host, handler, request_body, verbose=0): # issue XML-RPC request @@ -226,7 +226,7 @@ class addAuthTransport: h = self.make_connection(host) if verbose: h.set_debuglevel(1) - + tries = 0 atype = None realm = None @@ -246,7 +246,7 @@ class addAuthTransport: resp = h._conn.getresponse() # except BadStatusLine, e: tries += 1 - + if resp.status == 401: if 'www-authenticate' in resp.msg: (atype,realm) = resp.msg.getheader('www-authenticate').split(' ',1) @@ -258,7 +258,7 @@ class addAuthTransport: _logger.debug("Resp: %r %r", resp.version,resp.isclosed(), resp.will_close) _logger.debug("Want to do auth %s for realm %s", atype, realm) if atype != 'Basic': - raise ProtocolError(host+handler, 403, + raise ProtocolError(host+handler, 403, "Unknown authentication method: %s" % atype, resp.msg) continue # with the outer while loop else: @@ -268,14 +268,14 @@ class addAuthTransport: if resp.status != 200: raise ProtocolError( host + handler, resp.status, resp.reason, resp.msg ) - + self.verbose = verbose - + try: sock = h._conn.sock except AttributeError: sock = None - + return self._parse_response(h.getfile(), sock, resp) raise ProtocolError(host+handler, 403, "No authentication.",'') @@ -302,7 +302,7 @@ class HTTPSConnection(httplib.HTTPSConnection): self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ca_certs=ca_certs, cert_reqs=cert_reqs) - + def getpeercert(self): import ssl @@ -316,14 +316,14 @@ class HTTPSConnection(httplib.HTTPSConnection): if cert[0-lf] != '\n': cert = cert[:0-lf]+'\n'+cert[0-lf:] _logger.debug("len-footer: %s cert: %r", lf, cert[0-lf]) - + return cert class DAVClient(object): """An instance of a WebDAV client, connected to the OpenERP server """ - + def __init__(self, user=None, passwd=None, dbg=0, use_ssl=False, useragent=False, timeout=None): if use_ssl: self.host = config.get_misc('httpsd', 'interface', False) @@ -353,10 +353,10 @@ class DAVClient(object): def get_creds(self, obj, cr, uid): """Read back the user credentials from cr, uid - + @param obj is any orm object, in order to use its pool @param uid is the numeric id, which we will try to reverse resolve - + note: this is a hackish way to get the credentials. It is expected to break if "base_crypt" is used. """ @@ -366,7 +366,7 @@ class DAVClient(object): self.user = res[0]['login'] self.passwd = res[0]['password'] if self.passwd.startswith('$1$'): - # md5 by base crypt. We cannot decode, wild guess + # md5 by base crypt. We cannot decode, wild guess # that passwd = login self.passwd = self.user return True @@ -415,7 +415,7 @@ class DAVClient(object): auths = base64.encodestring(self.user + ':' + self.passwd) if auths[-1] == "\n": auths = auths[:-1] - hdrs['Authorization']= 'Basic '+ auths + hdrs['Authorization']= 'Basic '+ auths #sleep(1) conn.request(method, path, body, hdrs ) r1 = conn.getresponse() @@ -437,7 +437,7 @@ class DAVClient(object): doc = xml.dom.minidom.parseString(data1) _logger.debug("XML Body:\n %s", doc.toprettyxml(indent="\t")) except Exception: - _logger.warning("cannot print xml", exc_info=True) + _logger.warning("Cannot print XML.", exc_info=True) pass conn.close() return r1.status, r1.msg, data1 @@ -475,10 +475,10 @@ class DAVClient(object): assert s == 200, "Status: %r" % s assert 'OPTIONS' in m.getheader('Allow') _logger.debug('Options: %r', m.getheader('Allow')) - + if expect: self._assert_headers(expect, m) - + def _parse_prop_response(self, data): """ Parse a propfind/propname response """ @@ -488,7 +488,7 @@ class DAVClient(object): if node.nodeType == node.TEXT_NODE: rc.append(node.data) return ''.join(rc) - + def getElements(node, namespaces=None, strict=False): for cnod in node.childNodes: if cnod.nodeType != node.ELEMENT_NODE: @@ -534,10 +534,10 @@ class DAVClient(object): rstatus = int(sta) else: _logger.debug("What is <%s> inside a <propstat>?", pno.tagName) - + else: _logger.debug("Unknown node: %s", cno.tagName) - + res.setdefault(href,[]).append((status, res_nss)) return res @@ -558,7 +558,7 @@ class DAVClient(object): propstr += '<ns%d:%s xmlns:ns%d="%s" />' %(nscount, p, nscount, ns) nscount += 1 propstr += '</prop>' - + body="""<?xml version="1.0" encoding="utf-8"?> <propfind xmlns="DAV:">%s</propfind>""" % propstr hdrs = { 'Content-Type': 'text/xml; charset=utf-8', @@ -566,7 +566,7 @@ class DAVClient(object): 'Depth': depth, } - s, m, d = self._http_request(self.davpath + path, method='PROPFIND', + s, m, d = self._http_request(self.davpath + path, method='PROPFIND', hdrs=hdrs, body=body) assert s == 207, "Bad status: %s" % s ctype = m.getheader('Content-Type').split(';',1)[0] @@ -578,7 +578,7 @@ class DAVClient(object): else: assert len(res) >= 1 return res - + def gd_propname(self, path, depth=0): body="""<?xml version="1.0" encoding="utf-8"?> @@ -587,7 +587,7 @@ class DAVClient(object): 'Accept': 'text/xml', 'Depth': depth } - s, m, d = self._http_request(self.davpath + path, method='PROPFIND', + s, m, d = self._http_request(self.davpath + path, method='PROPFIND', hdrs=hdrs, body=body) assert s == 207, "Bad status: %s" % s ctype = m.getheader('Content-Type').split(';',1)[0] @@ -605,7 +605,7 @@ class DAVClient(object): def gd_lsl(self, path): """ Return a list of 'ls -l' kind of data for a folder - + This is based on propfind. """ @@ -616,7 +616,7 @@ class DAVClient(object): propnames = [ l[1] for l in lspairs] propres = self.gd_propfind(path, props=propnames, depth=1) - + res = [] for href, pr in propres.items(): lsline = {} @@ -638,9 +638,9 @@ class DAVClient(object): lsline[lsp[0]] = lsp[2] else: _logger.debug("Strange status: %s", st) - + res.append(lsline) - + return res def gd_get(self, path, crange=None, mime=None, compare=None): @@ -683,7 +683,7 @@ class DAVClient(object): return ctype, rrange, d def gd_put(self, path, body=None, srcpath=None, mime=None, noclobber=False, ): - """ HTTP PUT + """ HTTP PUT @param noclobber will prevent overwritting a resource (If-None-Match) @param mime will set the content-type """ @@ -698,7 +698,7 @@ class DAVClient(object): hdrs['Content-Type'] = mime if noclobber: hdrs['If-None-Match'] = '*' - s, m, d = self._http_request(self.davpath + path, method='PUT', + s, m, d = self._http_request(self.davpath + path, method='PUT', hdrs=hdrs, body=body) assert s == (201), "Bad status: %s" % s etag = m.getheader('ETag') diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index 427a6f57d53..28909e61167 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -73,7 +73,7 @@ def OpenDAVConfig(**kw): class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): verbose = False - + protocol_version = 'HTTP/1.1' _HTTP_OPTIONS= { 'DAV' : ['1', '2'], 'Allow' : [ 'GET', 'HEAD', 'COPY', 'MOVE', 'POST', 'PUT', @@ -304,7 +304,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): res = dc.unlock(uri, token) except DAV_Error, (ec, dd): return self.send_status(ec, dd) - + if res == True: self.send_body(None, '204', 'OK', 'Resource unlocked.') else: @@ -338,7 +338,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): if isinstance(ldif, list): if len(ldif) !=1 or (not isinstance(ldif[0], TagList)) \ or len(ldif[0].list) != 1: - raise DAV_Error(400, "Cannot accept multiple tokens!") + raise DAV_Error(400, "Cannot accept multiple tokens.") ldif = ldif[0].list[0] if ldif[0] == '<' and ldif[-1] == '>': ldif = ldif[1:-1] @@ -352,7 +352,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): lock_data.update(self._lock_unlock_parse(body)) if lock_data['refresh'] and not lock_data.get('token', False): - raise DAV_Error(400, 'Lock refresh must specify token!') + raise DAV_Error(400, 'Lock refresh must specify token.') lock_data['depth'] = depth @@ -487,7 +487,7 @@ class dummy_dav_interface(object): class DAVStaticHandler(http_server.StaticHTTPHandler): """ A variant of the Static handler, which will serve dummy DAV requests """ - + verbose = False protocol_version = 'HTTP/1.1' _HTTP_OPTIONS= { 'DAV' : ['1', '2'], @@ -503,13 +503,13 @@ class DAVStaticHandler(http_server.StaticHTTPHandler): self.end_headers() if hasattr(self, '_flush'): self._flush() - + if self.command != 'HEAD': self.wfile.write(content) def do_PROPFIND(self): """Answer to PROPFIND with generic data. - + A rough copy of python-webdav's do_PROPFIND, but hacked to work statically. """ @@ -575,7 +575,7 @@ try: handler._config = conf reg_http_service(directory, DAVHandler, DAVAuthProvider) _logger.info("WebDAV service registered at path: %s/ "% directory) - + if not (config.get_misc('webdav', 'no_root_hack', False)): # Now, replace the static http handler with the dav-enabled one. # If a static-http service has been specified for our server, then @@ -592,7 +592,7 @@ try: # an _ugly_ hack: we put that dir back in tools.config.misc, so that # the StaticHttpHandler can find its dir_path. config.misc.setdefault('static-http',{})['dir_path'] = dir_path - + reg_http_service('/', DAVStaticHandler) except Exception, e: @@ -617,10 +617,10 @@ def init_well_known(): init_well_known() class PrincipalsRedirect(RedirectHTTPHandler): - - + + redirect_paths = {} - + def _find_redirect(self): for b, r in self.redirect_paths.items(): if self.path.startswith(b): @@ -628,7 +628,7 @@ class PrincipalsRedirect(RedirectHTTPHandler): return False def init_principals_redirect(): - """ Some devices like the iPhone will look under /principals/users/xxx for + """ Some devices like the iPhone will look under /principals/users/xxx for the user's properties. In OpenERP we _cannot_ have a stray /principals/... working path, since we have a database path and the /webdav/ component. So, the best solution is to redirect the url with 301. Luckily, it does work in |
