Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
a7780f71
Commit
a7780f71
authored
Feb 25, 2019
by
antirez
Browse files
Merge branch 'gopher' into unstable
parents
21f92e9e
40a01a94
Changes
7
Show whitespace changes
Inline
Side-by-side
redis.conf
View file @
a7780f71
...
@@ -1183,6 +1183,61 @@ latency-monitor-threshold 0
...
@@ -1183,6 +1183,61 @@ latency-monitor-threshold 0
# specify at least one of K or E, no events will be delivered.
# specify at least one of K or E, no events will be delivered.
notify
-
keyspace
-
events
""
notify
-
keyspace
-
events
""
############################### GOPHER SERVER #################################
# Redis contains an implementation of the Gopher protocol, as specified in
# the RFC 1436 (https://www.ietf.org/rfc/rfc1436.txt).
#
# The Gopher protocol was very popular in the late '90s. It is an alternative
# to the web, and the implementation both server and client side is so simple
# that the Redis server has just 100 lines of code in order to implement this
# support.
#
# What do you do with Gopher nowadays? Well Gopher never *really* died, and
# lately there is a movement in order for the Gopher more hierarchical content
# composed of just plain text documents to be resurrected. Some want a simpler
# internet, others believe that the mainstream internet became too much
# controlled, and it's cool to create an alternative space for people that
# want a bit of fresh air.
#
# Anyway for the 10nth birthday of the Redis, we gave it the Gopher protocol
# as a gift.
#
# --- HOW IT WORKS? ---
#
# The Redis Gopher support uses the inline protocol of Redis, and specifically
# two kind of inline requests that were anyway illegal: an empty request
# or any request that starts with "/" (there are no Redis commands starting
# with such a slash). Normal RESP2/RESP3 requests are completely out of the
# path of the Gopher protocol implementation and are served as usually as well.
#
# If you open a connection to Redis when Gopher is enabled and send it
# a string like "/foo", if there is a key named "/foo" it is served via the
# Gopher protocol.
#
# In order to create a real Gopher "hole" (the name of a Gopher site in Gopher
# talking), you likely need a script like the following:
#
# https://github.com/antirez/gopher2redis
#
# --- SECURITY WARNING ---
#
# If you plan to put Redis on the internet in a publicly accessible address
# to server Gopher pages MAKE SURE TO SET A PASSWORD to the instance.
# Once a password is set:
#
# 1. The Gopher server (when enabled, not by default) will kill serve
# content via Gopher.
# 2. However other commands cannot be called before the client will
# authenticate.
#
# So use the 'requirepass' option to protect your instance.
#
# To enable Gopher support uncomment the following line and set
# the option from no (the default) to yes.
#
# gopher-enabled no
############################### ADVANCED CONFIG ###############################
############################### ADVANCED CONFIG ###############################
# Hashes are encoded using a memory efficient data structure when they have a
# Hashes are encoded using a memory efficient data structure when they have a
...
...
src/Makefile
View file @
a7780f71
...
@@ -164,7 +164,7 @@ endif
...
@@ -164,7 +164,7 @@ endif
REDIS_SERVER_NAME
=
redis-server
REDIS_SERVER_NAME
=
redis-server
REDIS_SENTINEL_NAME
=
redis-sentinel
REDIS_SENTINEL_NAME
=
redis-sentinel
REDIS_SERVER_OBJ
=
adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o acl.o
REDIS_SERVER_OBJ
=
adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o acl.o
gopher.o
REDIS_CLI_NAME
=
redis-cli
REDIS_CLI_NAME
=
redis-cli
REDIS_CLI_OBJ
=
anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o siphash.o crc16.o
REDIS_CLI_OBJ
=
anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o siphash.o crc16.o
REDIS_BENCHMARK_NAME
=
redis-benchmark
REDIS_BENCHMARK_NAME
=
redis-benchmark
...
...
src/config.c
View file @
a7780f71
...
@@ -216,6 +216,10 @@ void loadServerConfigFromString(char *config) {
...
@@ -216,6 +216,10 @@ void loadServerConfigFromString(char *config) {
if
((
server
.
protected_mode
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
if
((
server
.
protected_mode
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"gopher-enabled"
)
&&
argc
==
2
)
{
if
((
server
.
gopher_enabled
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"port"
)
&&
argc
==
2
)
{
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"port"
)
&&
argc
==
2
)
{
server
.
port
=
atoi
(
argv
[
1
]);
server
.
port
=
atoi
(
argv
[
1
]);
if
(
server
.
port
<
0
||
server
.
port
>
65535
)
{
if
(
server
.
port
<
0
||
server
.
port
>
65535
)
{
...
@@ -1141,6 +1145,8 @@ void configSetCommand(client *c) {
...
@@ -1141,6 +1145,8 @@ void configSetCommand(client *c) {
#endif
#endif
}
config_set_bool_field
(
}
config_set_bool_field
(
"protected-mode"
,
server
.
protected_mode
)
{
"protected-mode"
,
server
.
protected_mode
)
{
}
config_set_bool_field
(
"gopher-enabled"
,
server
.
gopher_enabled
)
{
}
config_set_bool_field
(
}
config_set_bool_field
(
"stop-writes-on-bgsave-error"
,
server
.
stop_writes_on_bgsave_err
)
{
"stop-writes-on-bgsave-error"
,
server
.
stop_writes_on_bgsave_err
)
{
}
config_set_bool_field
(
}
config_set_bool_field
(
...
@@ -1472,6 +1478,7 @@ void configGetCommand(client *c) {
...
@@ -1472,6 +1478,7 @@ void configGetCommand(client *c) {
config_get_bool_field
(
"activerehashing"
,
server
.
activerehashing
);
config_get_bool_field
(
"activerehashing"
,
server
.
activerehashing
);
config_get_bool_field
(
"activedefrag"
,
server
.
active_defrag_enabled
);
config_get_bool_field
(
"activedefrag"
,
server
.
active_defrag_enabled
);
config_get_bool_field
(
"protected-mode"
,
server
.
protected_mode
);
config_get_bool_field
(
"protected-mode"
,
server
.
protected_mode
);
config_get_bool_field
(
"gopher-enabled"
,
server
.
gopher_enabled
);
config_get_bool_field
(
"repl-disable-tcp-nodelay"
,
config_get_bool_field
(
"repl-disable-tcp-nodelay"
,
server
.
repl_disable_tcp_nodelay
);
server
.
repl_disable_tcp_nodelay
);
config_get_bool_field
(
"repl-diskless-sync"
,
config_get_bool_field
(
"repl-diskless-sync"
,
...
@@ -2301,6 +2308,7 @@ int rewriteConfig(char *path) {
...
@@ -2301,6 +2308,7 @@ int rewriteConfig(char *path) {
rewriteConfigYesNoOption
(
state
,
"activerehashing"
,
server
.
activerehashing
,
CONFIG_DEFAULT_ACTIVE_REHASHING
);
rewriteConfigYesNoOption
(
state
,
"activerehashing"
,
server
.
activerehashing
,
CONFIG_DEFAULT_ACTIVE_REHASHING
);
rewriteConfigYesNoOption
(
state
,
"activedefrag"
,
server
.
active_defrag_enabled
,
CONFIG_DEFAULT_ACTIVE_DEFRAG
);
rewriteConfigYesNoOption
(
state
,
"activedefrag"
,
server
.
active_defrag_enabled
,
CONFIG_DEFAULT_ACTIVE_DEFRAG
);
rewriteConfigYesNoOption
(
state
,
"protected-mode"
,
server
.
protected_mode
,
CONFIG_DEFAULT_PROTECTED_MODE
);
rewriteConfigYesNoOption
(
state
,
"protected-mode"
,
server
.
protected_mode
,
CONFIG_DEFAULT_PROTECTED_MODE
);
rewriteConfigYesNoOption
(
state
,
"gopher-enabled"
,
server
.
gopher_enabled
,
CONFIG_DEFAULT_GOPHER_ENABLED
);
rewriteConfigClientoutputbufferlimitOption
(
state
);
rewriteConfigClientoutputbufferlimitOption
(
state
);
rewriteConfigNumericalOption
(
state
,
"hz"
,
server
.
config_hz
,
CONFIG_DEFAULT_HZ
);
rewriteConfigNumericalOption
(
state
,
"hz"
,
server
.
config_hz
,
CONFIG_DEFAULT_HZ
);
rewriteConfigYesNoOption
(
state
,
"aof-rewrite-incremental-fsync"
,
server
.
aof_rewrite_incremental_fsync
,
CONFIG_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC
);
rewriteConfigYesNoOption
(
state
,
"aof-rewrite-incremental-fsync"
,
server
.
aof_rewrite_incremental_fsync
,
CONFIG_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC
);
...
...
src/gopher.c
0 → 100644
View file @
a7780f71
/*
* Copyright (c) 2019, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "server.h"
/* Emit an item in Gopher directory listing format:
* <type><descr><TAB><selector><TAB><hostname><TAB><port>
* If descr or selector are NULL, then the "(NULL)" string is used instead. */
void
addReplyGopherItem
(
client
*
c
,
const
char
*
type
,
const
char
*
descr
,
const
char
*
selector
,
const
char
*
hostname
,
int
port
)
{
sds
item
=
sdscatfmt
(
sdsempty
(),
"%s%s
\t
%s
\t
%s
\t
%i
\r\n
"
,
type
,
descr
,
selector
?
selector
:
"(NULL)"
,
hostname
?
hostname
:
"(NULL)"
,
port
);
addReplyProto
(
c
,
item
,
sdslen
(
item
));
sdsfree
(
item
);
}
/* This is called by processInputBuffer() when an inline request is processed
* with Gopher mode enabled, and the request happens to have zero or just one
* argument. In such case we get the relevant key and reply using the Gopher
* protocol. */
void
processGopherRequest
(
client
*
c
)
{
robj
*
keyname
=
c
->
argc
==
0
?
createStringObject
(
"/"
,
1
)
:
c
->
argv
[
0
];
robj
*
o
=
lookupKeyRead
(
c
->
db
,
keyname
);
/* If there is no such key, return with a Gopher error. */
if
(
o
==
NULL
||
o
->
type
!=
OBJ_STRING
)
{
char
*
errstr
;
if
(
o
==
NULL
)
errstr
=
"Error: no content at the specified key"
;
else
errstr
=
"Error: selected key type is invalid "
"for Gopher output"
;
addReplyGopherItem
(
c
,
"i"
,
errstr
,
NULL
,
NULL
,
0
);
addReplyGopherItem
(
c
,
"i"
,
"Redis Gopher server"
,
NULL
,
NULL
,
0
);
}
else
{
addReply
(
c
,
o
);
}
/* Cleanup, also make sure to emit the final ".CRLF" line. Note that
* the connection will be closed immediately after this because the client
* will be flagged with CLIENT_CLOSE_AFTER_REPLY, in accordance with the
* Gopher protocol. */
if
(
c
->
argc
==
0
)
decrRefCount
(
keyname
);
/* Note that in theory we should terminate the Gopher request with
* ".<CR><LF>" (called Lastline in the RFC) like that:
*
* addReplyProto(c,".\r\n",3);
*
* However after examining the current clients landscape, it's probably
* going to do more harm than good for several reasons:
*
* 1. Clients should not have any issue with missing .<CR><LF> as for
* specification, and in the real world indeed certain servers
* implementations never used to send the terminator.
*
* 2. Redis does not know if it's serving a text file or a binary file:
* at the same time clients will not remove the ".<CR><LF>" bytes at
* tne end when downloading a binary file from the server, so adding
* the "Lastline" terminator without knowing the content is just
* dangerous.
*
* 3. The utility gopher2redis.rb that we provide for Redis, and any
* other similar tool you may use as Gopher authoring system for
* Redis, can just add the "Lastline" when needed.
*/
}
src/networking.c
View file @
a7780f71
...
@@ -1548,6 +1548,14 @@ void processInputBuffer(client *c) {
...
@@ -1548,6 +1548,14 @@ void processInputBuffer(client *c) {
if
(
c
->
reqtype
==
PROTO_REQ_INLINE
)
{
if
(
c
->
reqtype
==
PROTO_REQ_INLINE
)
{
if
(
processInlineBuffer
(
c
)
!=
C_OK
)
break
;
if
(
processInlineBuffer
(
c
)
!=
C_OK
)
break
;
/* If the Gopher mode and we got zero or one argument, process
* the request in Gopher mode. */
if
(
server
.
gopher_enabled
&&
(
c
->
argc
==
1
||
c
->
argc
==
0
))
{
processGopherRequest
(
c
);
resetClient
(
c
);
c
->
flags
|=
CLIENT_CLOSE_AFTER_REPLY
;
break
;
}
}
else
if
(
c
->
reqtype
==
PROTO_REQ_MULTIBULK
)
{
}
else
if
(
c
->
reqtype
==
PROTO_REQ_MULTIBULK
)
{
if
(
processMultibulkBuffer
(
c
)
!=
C_OK
)
break
;
if
(
processMultibulkBuffer
(
c
)
!=
C_OK
)
break
;
}
else
{
}
else
{
...
...
src/server.c
View file @
a7780f71
...
@@ -2222,6 +2222,7 @@ void initServerConfig(void) {
...
@@ -2222,6 +2222,7 @@ void initServerConfig(void) {
server
.
ipfd_count
=
0
;
server
.
ipfd_count
=
0
;
server
.
sofd
=
-
1
;
server
.
sofd
=
-
1
;
server
.
protected_mode
=
CONFIG_DEFAULT_PROTECTED_MODE
;
server
.
protected_mode
=
CONFIG_DEFAULT_PROTECTED_MODE
;
server
.
gopher_enabled
=
CONFIG_DEFAULT_GOPHER_ENABLED
;
server
.
dbnum
=
CONFIG_DEFAULT_DBNUM
;
server
.
dbnum
=
CONFIG_DEFAULT_DBNUM
;
server
.
verbosity
=
CONFIG_DEFAULT_VERBOSITY
;
server
.
verbosity
=
CONFIG_DEFAULT_VERBOSITY
;
server
.
maxidletime
=
CONFIG_DEFAULT_CLIENT_TIMEOUT
;
server
.
maxidletime
=
CONFIG_DEFAULT_CLIENT_TIMEOUT
;
...
...
src/server.h
View file @
a7780f71
...
@@ -121,6 +121,7 @@ typedef long long mstime_t; /* millisecond time type. */
...
@@ -121,6 +121,7 @@ typedef long long mstime_t; /* millisecond time type. */
#define CONFIG_DEFAULT_UNIX_SOCKET_PERM 0
#define CONFIG_DEFAULT_UNIX_SOCKET_PERM 0
#define CONFIG_DEFAULT_TCP_KEEPALIVE 300
#define CONFIG_DEFAULT_TCP_KEEPALIVE 300
#define CONFIG_DEFAULT_PROTECTED_MODE 1
#define CONFIG_DEFAULT_PROTECTED_MODE 1
#define CONFIG_DEFAULT_GOPHER_ENABLED 0
#define CONFIG_DEFAULT_LOGFILE ""
#define CONFIG_DEFAULT_LOGFILE ""
#define CONFIG_DEFAULT_SYSLOG_ENABLED 0
#define CONFIG_DEFAULT_SYSLOG_ENABLED 0
#define CONFIG_DEFAULT_STOP_WRITES_ON_BGSAVE_ERROR 1
#define CONFIG_DEFAULT_STOP_WRITES_ON_BGSAVE_ERROR 1
...
@@ -1054,6 +1055,8 @@ struct redisServer {
...
@@ -1054,6 +1055,8 @@ struct redisServer {
dict
*
migrate_cached_sockets
;
/* MIGRATE cached sockets */
dict
*
migrate_cached_sockets
;
/* MIGRATE cached sockets */
uint64_t
next_client_id
;
/* Next client unique ID. Incremental. */
uint64_t
next_client_id
;
/* Next client unique ID. Incremental. */
int
protected_mode
;
/* Don't accept external connections. */
int
protected_mode
;
/* Don't accept external connections. */
int
gopher_enabled
;
/* If true the server will reply to gopher
queries. Will still serve RESP2 queries. */
/* RDB / AOF loading information */
/* RDB / AOF loading information */
int
loading
;
/* We are loading data from disk if true */
int
loading
;
/* We are loading data from disk if true */
off_t
loading_total_bytes
;
off_t
loading_total_bytes
;
...
@@ -1511,6 +1514,7 @@ void setDeferredAttributeLen(client *c, void *node, long length);
...
@@ -1511,6 +1514,7 @@ void setDeferredAttributeLen(client *c, void *node, long length);
void
setDeferredPushLen
(
client
*
c
,
void
*
node
,
long
length
);
void
setDeferredPushLen
(
client
*
c
,
void
*
node
,
long
length
);
void
processInputBuffer
(
client
*
c
);
void
processInputBuffer
(
client
*
c
);
void
processInputBufferAndReplicate
(
client
*
c
);
void
processInputBufferAndReplicate
(
client
*
c
);
void
processGopherRequest
(
client
*
c
);
void
acceptHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
acceptHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
acceptTcpHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
acceptTcpHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
acceptUnixHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
acceptUnixHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment