« index

Coverage for /Users/yunong/workspace/node-restify/lib/plugins/body_reader.js : 98%

128 lines | 126 run | 2 missing | 0 partial | 21 blocks | 20 blocks run | 1 blocks missing

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

  // Copyright 2012 Mark Cavage, Inc.  All rights reserved.
  
  var crypto = require('crypto');
  var zlib = require('zlib');
  
  var assert = require('assert-plus');
  
  var errors = require('../errors');
  
  
  ///--- Globals
  
  var BadDigestError = errors.BadDigestError;
  var InvalidContentError = errors.InvalidContentError;
  var RequestEntityTooLargeError = errors.RequestEntityTooLargeError;
  
  var MD5_MSG = 'Content-MD5 \'%s\' didn\'t match \'%s\'';
  
  
  ///--- Helpers
  
  function createBodyWriter(req) {
      var buffers = [];
  
      var contentType = req.contentType();
      var isText = false;
      if (!contentType ||
          contentType === 'application/json' ||
          contentType === 'application/x-www-form-urlencoded' ||
          contentType === 'multipart/form-data' ||
          contentType.substr(0, 5) === 'text/') {
          isText = true;
      }
  
      req.body = new Buffer(0);
      return {
          write: function (chunk) { buffers.push(chunk); },
          end: function () {
              req.body = Buffer.concat(buffers);
              if (isText)
                  req.body = req.body.toString('utf8');
          }
      };
  }
  
  
  ///--- API
  
  function bodyReader(options) {
      options = options || {};
      assert.object(options, 'options');
  
      var maxBodySize = options.maxBodySize || 0;
  
      function readBody(req, res, next) {
          if ((req.getContentLength() === 0 && !req.isChunked()) ||
              req.contentType() === 'multipart/form-data' ||
              req.contentType() === 'application/octet-stream') {
              next();
              return;
          }
          var bodyWriter = createBodyWriter(req);
  
          function done() {
              bodyWriter.end();
  
              if (maxBodySize && bytesReceived > maxBodySize) {
                  var msg = 'Request body size exceeds ' +
                      maxBodySize;
                  next(new RequestEntityTooLargeError(msg));
                  return;
              }
  
              if (!req.body.length) {
                  next();
                  return;
              }
  
              if (hash && md5 !== (digest = hash.digest('base64'))) {
                  next(new BadDigestError(MD5_MSG, md5, digest));
                  return;
              }
  
              next();
          }
  
          var bytesReceived = 0;
          var digest;
          var gz;
          var hash;
          var md5;
          if ((md5 = req.headers['content-md5']))
              hash = crypto.createHash('md5');
  
          if (req.headers['content-encoding'] === 'gzip') {
              gz = zlib.createGunzip();
              gz.on('data', bodyWriter.write);
              gz.once('end', done);
              req.once('end', gz.end.bind(gz));
          } else {
              req.once('end', done);
          }
  
          req.on('data', function onRequestData(chunk) {
              if (maxBodySize) {
                  bytesReceived += chunk.length;
                  if (bytesReceived > maxBodySize)
                      return;
              }
  
              if (hash)
                  hash.update(chunk, 'binary');
  
              if (gz) {
                  gz.write(chunk);
              } else {
                  bodyWriter.write(chunk);
              }
          });
  
          req.once('error', next);
          req.resume();
      }
  
      return (readBody);
  }
  
  module.exports = bodyReader;
« index | cover.io