« index

Coverage for /Users/kris/q-io/http-apps/cookie.js : 86%

152 lines | 131 run | 21 missing | 2 partial | 33 blocks | 24 blocks run | 9 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

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

  var Q = require("q");
  var Cookie = require("../http-cookie");
  
  exports.CookieJar = function (app) {
      var hostCookies = {}; // to {} of pathCookies to [] of cookies
      return function (request) {
  
          var hosts = allHostsContaining(request.headers.host);
  
          var now = new Date();
  
          var requestCookies = concat(hosts.map(function (host) {
  
              // delete expired cookies
              for (var host in hostCookies) {
                  var pathCookies = hostCookies[host];
                  for (var path in pathCookies) {
                      var cookies = pathCookies[path];
                      for (var name in cookies) {
                          var cookie = cookies[name];
                          if (cookie.expires && cookie.expires > now) {
                              delete cookie[name];
                          }
                      }
                  }
              }
  
              // collect applicable cookies
              return concat(
                  Object.keys(hostCookies)
                  .map(function (host) {
                      if (!hostContains(host, request.headers.host))
                          return [];
                      var pathCookies = hostCookies[host];
                      return concat(
                          Object.keys(pathCookies)
                          .map(function (path) {
                              if (!pathContains(path, request.path))
                                  return [];
                              var cookies = pathCookies[path];
                              return (
                                  Object.keys(cookies)
                                  .map(function (name) {
                                      return cookies[name];
                                  })
                                  .filter(function (cookie) {
                                      return cookie.secure ?
                                          request.ssl :
                                          true;
                                  })
                              );
                          })
                      )
                  })
              );
  
          }));
  
          if (requestCookies.length) {
              request.headers["cookie"] = (
                  requestCookies
                  .map(function (cookie) {
                      return Cookie.stringify(
                          cookie.key,
                          cookie.value,
                          cookie
                      );
                  })
                  .join("; ")
              );
          }
  
          return Q.when(app.apply(this, arguments), function (response) {
              response.headers = response.headers || {};
              if (response.headers["set-cookie"]) {
                  var requestHost = ipRe.test(request.headers.host) ?
                      request.headers.host :
                      "." + request.headers.host;
                  // normalize to array
                  if (!Array.isArray(response.headers["set-cookie"])) {
                      response.headers["set-cookie"] = [response.headers["set-cookie"]];
                  }
                  response.headers["set-cookie"].forEach(function (cookie) {
                      var date = response.headers["date"] ?
                          new Date(response.headers["date"]) :
                          new Date();
                      cookie = Cookie.parse(cookie, date);
                      // ignore illegal host
                      if (cookie.host && !hostContains(requestHost, cookie.host))
                          delete cookie.host;
                      var host = requestHost || cookie.host;
                      var path = cookie.path || "/";
                      var pathCookies = hostCookies[host] = hostCookies[host] || {};
                      var cookies = pathCookies[path] = pathCookies[path] || {};
                      cookies[cookie.key] = cookie;
                  })
                  delete response.headers["set-cookie"];
              }
  
              return response;
          });
  
      };
  };
  
  var ipRe = /^\d+\.\d+\.\d+\.\d+$/;
  
  function allHostsContaining(content) {
      if (ipRe.test(content)) {
          return [content];
      } if (content === "localhost") {
          return [content];
      } else {
          var parts = content.split(".");
          var hosts = [];
          while (parts.length > 1) {
              hosts.push("." + parts.join("."));
              parts.shift();
          }
          return hosts;
      }
  }
  
  function hostContains(container, content) {
      if (ipRe.test(container) || ipRe.test(content)) {
          return container === content;
      } else if (/^\./.test(container)) {
          return (
              content.lastIndexOf(container) ===
              content.length - container.length
          ) || (
              container.slice(1) === content
          );
      } else {
          return container === content;
      }
  };
  
  function pathContains(container, content) {
      if (/^\/$/.test(container)) {
          return content.indexOf(container) === 0;
      } else {
          return (
              content === container ||
              content.indexOf(container + "/") === 0
          );
      }
  }
  
  function concat(arrays) {
      return [].concat.apply([], arrays);
  }
« index | cover.io