Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

""" 

FastCGI (or SCGI, or AJP1.3 ...) server that implements the WSGI protocol. 

 

Uses the flup python package: http://www.saddi.com/software/flup/ 

 

This is a adaptation of the flup package to add FastCGI server support 

to run Django apps from Web servers that support the FastCGI protocol. 

This module can be run standalone or from the django-admin / manage.py 

scripts using the "runfcgi" directive. 

 

Run with the extra option "help" for a list of additional options you can 

pass to this server. 

""" 

 

import os 

import sys 

from django.utils import importlib 

 

__version__ = "0.1" 

__all__ = ["runfastcgi"] 

 

FASTCGI_HELP = r""" 

  Run this project as a fastcgi (or some other protocol supported 

  by flup) application. To do this, the flup package from 

  http://www.saddi.com/software/flup/ is required. 

 

   runfcgi [options] [fcgi settings] 

 

Optional Fcgi settings: (setting=value) 

  protocol=PROTOCOL    fcgi, scgi, ajp, ... (default fcgi) 

  host=HOSTNAME        hostname to listen on. 

  port=PORTNUM         port to listen on. 

  socket=FILE          UNIX socket to listen on. 

  method=IMPL          prefork or threaded (default prefork). 

  maxrequests=NUMBER   number of requests a child handles before it is 

                       killed and a new child is forked (0 = no limit). 

  maxspare=NUMBER      max number of spare processes / threads. 

  minspare=NUMBER      min number of spare processes / threads. 

  maxchildren=NUMBER   hard limit number of processes / threads. 

  daemonize=BOOL       whether to detach from terminal. 

  pidfile=FILE         write the spawned process-id to this file. 

  workdir=DIRECTORY    change to this directory when daemonizing. 

  debug=BOOL           set to true to enable flup tracebacks. 

  outlog=FILE          write stdout to this file. 

  errlog=FILE          write stderr to this file. 

  umask=UMASK          umask to use when daemonizing, in octal notation (default 022). 

 

Examples: 

  Run a "standard" fastcgi process on a file-descriptor 

  (for Web servers which spawn your processes for you) 

    $ manage.py runfcgi method=threaded 

 

  Run a scgi server on a TCP host/port 

    $ manage.py runfcgi protocol=scgi method=prefork host=127.0.0.1 port=8025 

 

  Run a fastcgi server on a UNIX domain socket (posix platforms only) 

    $ manage.py runfcgi method=prefork socket=/tmp/fcgi.sock 

 

  Run a fastCGI as a daemon and write the spawned PID in a file 

    $ manage.py runfcgi socket=/tmp/fcgi.sock method=prefork \ 

        daemonize=true pidfile=/var/run/django-fcgi.pid 

 

""" 

 

FASTCGI_OPTIONS = { 

    'protocol': 'fcgi', 

    'host': None, 

    'port': None, 

    'socket': None, 

    'method': 'fork', 

    'daemonize': None, 

    'workdir': '/', 

    'pidfile': None, 

    'maxspare': 5, 

    'minspare': 2, 

    'maxchildren': 50, 

    'maxrequests': 0, 

    'debug': None, 

    'outlog': None, 

    'errlog': None, 

    'umask': None, 

} 

 

def fastcgi_help(message=None): 

    print FASTCGI_HELP 

    if message: 

        print message 

    return False 

 

def runfastcgi(argset=[], **kwargs): 

    options = FASTCGI_OPTIONS.copy() 

    options.update(kwargs) 

    for x in argset: 

        if "=" in x: 

            k, v = x.split('=', 1) 

        else: 

            k, v = x, True 

        options[k.lower()] = v 

 

    if "help" in options: 

        return fastcgi_help() 

 

    try: 

        import flup 

    except ImportError, e: 

        print >> sys.stderr, "ERROR: %s" % e 

        print >> sys.stderr, "  Unable to load the flup package.  In order to run django" 

        print >> sys.stderr, "  as a FastCGI application, you will need to get flup from" 

        print >> sys.stderr, "  http://www.saddi.com/software/flup/   If you've already" 

        print >> sys.stderr, "  installed flup, then make sure you have it in your PYTHONPATH." 

        return False 

 

    flup_module = 'server.' + options['protocol'] 

 

    if options['method'] in ('prefork', 'fork'): 

        wsgi_opts = { 

            'maxSpare': int(options["maxspare"]), 

            'minSpare': int(options["minspare"]), 

            'maxChildren': int(options["maxchildren"]), 

            'maxRequests': int(options["maxrequests"]), 

        } 

        flup_module += '_fork' 

    elif options['method'] in ('thread', 'threaded'): 

        wsgi_opts = { 

            'maxSpare': int(options["maxspare"]), 

            'minSpare': int(options["minspare"]), 

            'maxThreads': int(options["maxchildren"]), 

        } 

    else: 

        return fastcgi_help("ERROR: Implementation must be one of prefork or thread.") 

 

    wsgi_opts['debug'] = options['debug'] is not None 

 

    try: 

        module = importlib.import_module('.%s' % flup_module, 'flup') 

        WSGIServer = module.WSGIServer 

    except: 

        print "Can't import flup." + flup_module 

        return False 

 

    # Prep up and go 

    from django.core.servers.basehttp import get_internal_wsgi_application 

 

    if options["host"] and options["port"] and not options["socket"]: 

        wsgi_opts['bindAddress'] = (options["host"], int(options["port"])) 

    elif options["socket"] and not options["host"] and not options["port"]: 

        wsgi_opts['bindAddress'] = options["socket"] 

    elif not options["socket"] and not options["host"] and not options["port"]: 

        wsgi_opts['bindAddress'] = None 

    else: 

        return fastcgi_help("Invalid combination of host, port, socket.") 

 

    if options["daemonize"] is None: 

        # Default to daemonizing if we're running on a socket/named pipe. 

        daemonize = (wsgi_opts['bindAddress'] is not None) 

    else: 

        if options["daemonize"].lower() in ('true', 'yes', 't'): 

            daemonize = True 

        elif options["daemonize"].lower() in ('false', 'no', 'f'): 

            daemonize = False 

        else: 

            return fastcgi_help("ERROR: Invalid option for daemonize parameter.") 

 

    daemon_kwargs = {} 

    if options['outlog']: 

        daemon_kwargs['out_log'] = options['outlog'] 

    if options['errlog']: 

        daemon_kwargs['err_log'] = options['errlog'] 

    if options['umask']: 

        daemon_kwargs['umask'] = int(options['umask'], 8) 

 

    if daemonize: 

        from django.utils.daemonize import become_daemon 

        become_daemon(our_home_dir=options["workdir"], **daemon_kwargs) 

 

    if options["pidfile"]: 

        fp = open(options["pidfile"], "w") 

        fp.write("%d\n" % os.getpid()) 

        fp.close() 

 

    WSGIServer(get_internal_wsgi_application(), **wsgi_opts).run() 

 

if __name__ == '__main__': 

    runfastcgi(sys.argv[1:])